4
0

stats.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. /*
  2. * Copyright (c) 2017-2020 Red Hat, Inc.
  3. *
  4. * All rights reserved.
  5. *
  6. * Authors: Christine Caulfield (ccaulfie@redhat.com)
  7. *
  8. * This software licensed under BSD license, the text of which follows:
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. * - Neither the name of the MontaVista Software, Inc. nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  32. * THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include <config.h>
  35. #include <sys/types.h>
  36. #include <sys/stat.h>
  37. #include <fcntl.h>
  38. #include <stdint.h>
  39. #include <stddef.h>
  40. #include <unistd.h>
  41. #include <libknet.h>
  42. #include <qb/qblist.h>
  43. #include <qb/qbipcs.h>
  44. #include <qb/qbipc_common.h>
  45. #include <corosync/corodefs.h>
  46. #include <corosync/coroapi.h>
  47. #include <corosync/logsys.h>
  48. #include <corosync/icmap.h>
  49. #include <corosync/totem/totemstats.h>
  50. #include "util.h"
  51. #include "ipcs_stats.h"
  52. #include "stats.h"
  53. LOGSYS_DECLARE_SUBSYS ("STATS");
  54. static qb_map_t *stats_map;
  55. /* Structure of an element in the schedmiss array */
  56. struct schedmiss_entry {
  57. uint64_t timestamp;
  58. float delay;
  59. };
  60. #define MAX_SCHEDMISS_EVENTS 10
  61. static struct schedmiss_entry schedmiss_event[MAX_SCHEDMISS_EVENTS];
  62. static unsigned int highest_schedmiss_event;
  63. #define SCHEDMISS_PREFIX "stats.schedmiss"
  64. /* Convert iterator number to text and a stats pointer */
  65. struct cs_stats_conv {
  66. enum {STAT_PG, STAT_SRP, STAT_KNET, STAT_KNET_HANDLE, STAT_IPCSC, STAT_IPCSG, STAT_SCHEDMISS} type;
  67. const char *name;
  68. const size_t offset;
  69. const icmap_value_types_t value_type;
  70. };
  71. struct cs_stats_conv cs_pg_stats[] = {
  72. { STAT_PG, "msg_queue_avail", offsetof(totempg_stats_t, msg_queue_avail), ICMAP_VALUETYPE_UINT32},
  73. { STAT_PG, "msg_reserved", offsetof(totempg_stats_t, msg_reserved), ICMAP_VALUETYPE_UINT32},
  74. };
  75. struct cs_stats_conv cs_srp_stats[] = {
  76. { STAT_SRP, "orf_token_tx", offsetof(totemsrp_stats_t, orf_token_tx), ICMAP_VALUETYPE_UINT64},
  77. { STAT_SRP, "orf_token_rx", offsetof(totemsrp_stats_t, orf_token_rx), ICMAP_VALUETYPE_UINT64},
  78. { STAT_SRP, "memb_merge_detect_tx", offsetof(totemsrp_stats_t, memb_merge_detect_tx), ICMAP_VALUETYPE_UINT64},
  79. { STAT_SRP, "memb_merge_detect_rx", offsetof(totemsrp_stats_t, memb_merge_detect_rx), ICMAP_VALUETYPE_UINT64},
  80. { STAT_SRP, "memb_join_tx", offsetof(totemsrp_stats_t, memb_join_tx), ICMAP_VALUETYPE_UINT64},
  81. { STAT_SRP, "memb_join_rx", offsetof(totemsrp_stats_t, memb_join_rx), ICMAP_VALUETYPE_UINT64},
  82. { STAT_SRP, "mcast_tx", offsetof(totemsrp_stats_t, mcast_tx), ICMAP_VALUETYPE_UINT64},
  83. { STAT_SRP, "mcast_retx", offsetof(totemsrp_stats_t, mcast_retx), ICMAP_VALUETYPE_UINT64},
  84. { STAT_SRP, "mcast_rx", offsetof(totemsrp_stats_t, mcast_rx), ICMAP_VALUETYPE_UINT64},
  85. { STAT_SRP, "memb_commit_token_tx", offsetof(totemsrp_stats_t, memb_commit_token_tx), ICMAP_VALUETYPE_UINT64},
  86. { STAT_SRP, "memb_commit_token_rx", offsetof(totemsrp_stats_t, memb_commit_token_rx), ICMAP_VALUETYPE_UINT64},
  87. { STAT_SRP, "token_hold_cancel_tx", offsetof(totemsrp_stats_t, token_hold_cancel_tx), ICMAP_VALUETYPE_UINT64},
  88. { STAT_SRP, "token_hold_cancel_rx", offsetof(totemsrp_stats_t, token_hold_cancel_rx), ICMAP_VALUETYPE_UINT64},
  89. { STAT_SRP, "operational_entered", offsetof(totemsrp_stats_t, operational_entered), ICMAP_VALUETYPE_UINT64},
  90. { STAT_SRP, "operational_token_lost", offsetof(totemsrp_stats_t, operational_token_lost), ICMAP_VALUETYPE_UINT64},
  91. { STAT_SRP, "gather_entered", offsetof(totemsrp_stats_t, gather_entered), ICMAP_VALUETYPE_UINT64},
  92. { STAT_SRP, "gather_token_lost", offsetof(totemsrp_stats_t, gather_token_lost), ICMAP_VALUETYPE_UINT64},
  93. { STAT_SRP, "commit_entered", offsetof(totemsrp_stats_t, commit_entered), ICMAP_VALUETYPE_UINT64},
  94. { STAT_SRP, "commit_token_lost", offsetof(totemsrp_stats_t, commit_token_lost), ICMAP_VALUETYPE_UINT64},
  95. { STAT_SRP, "recovery_entered", offsetof(totemsrp_stats_t, recovery_entered), ICMAP_VALUETYPE_UINT64},
  96. { STAT_SRP, "recovery_token_lost", offsetof(totemsrp_stats_t, recovery_token_lost), ICMAP_VALUETYPE_UINT64},
  97. { STAT_SRP, "consensus_timeouts", offsetof(totemsrp_stats_t, consensus_timeouts), ICMAP_VALUETYPE_UINT64},
  98. { STAT_SRP, "rx_msg_dropped", offsetof(totemsrp_stats_t, rx_msg_dropped), ICMAP_VALUETYPE_UINT64},
  99. { STAT_SRP, "time_since_token_last_received", offsetof(totemsrp_stats_t, time_since_token_last_received), ICMAP_VALUETYPE_UINT64},
  100. { STAT_SRP, "continuous_gather", offsetof(totemsrp_stats_t, continuous_gather), ICMAP_VALUETYPE_UINT32},
  101. { STAT_SRP, "continuous_sendmsg_failures", offsetof(totemsrp_stats_t, continuous_sendmsg_failures), ICMAP_VALUETYPE_UINT32},
  102. { STAT_SRP, "firewall_enabled_or_nic_failure", offsetof(totemsrp_stats_t, firewall_enabled_or_nic_failure), ICMAP_VALUETYPE_UINT8},
  103. { STAT_SRP, "mtt_rx_token", offsetof(totemsrp_stats_t, mtt_rx_token), ICMAP_VALUETYPE_UINT32},
  104. { STAT_SRP, "avg_token_workload", offsetof(totemsrp_stats_t, avg_token_workload), ICMAP_VALUETYPE_UINT32},
  105. { STAT_SRP, "avg_backlog_calc", offsetof(totemsrp_stats_t, avg_backlog_calc), ICMAP_VALUETYPE_UINT32},
  106. };
  107. struct cs_stats_conv cs_knet_stats[] = {
  108. { STAT_KNET, "enabled", offsetof(struct knet_link_status, enabled), ICMAP_VALUETYPE_UINT8},
  109. { STAT_KNET, "connected", offsetof(struct knet_link_status, connected), ICMAP_VALUETYPE_UINT8},
  110. { STAT_KNET, "mtu", offsetof(struct knet_link_status, mtu), ICMAP_VALUETYPE_UINT32},
  111. { STAT_KNET, "tx_data_packets", offsetof(struct knet_link_status, stats.tx_data_packets), ICMAP_VALUETYPE_UINT64},
  112. { STAT_KNET, "rx_data_packets", offsetof(struct knet_link_status, stats.rx_data_packets), ICMAP_VALUETYPE_UINT64},
  113. { STAT_KNET, "tx_data_bytes", offsetof(struct knet_link_status, stats.tx_data_bytes), ICMAP_VALUETYPE_UINT64},
  114. { STAT_KNET, "rx_data_bytes", offsetof(struct knet_link_status, stats.rx_data_bytes), ICMAP_VALUETYPE_UINT64},
  115. { STAT_KNET, "tx_ping_packets", offsetof(struct knet_link_status, stats.tx_ping_packets), ICMAP_VALUETYPE_UINT64},
  116. { STAT_KNET, "rx_ping_packets", offsetof(struct knet_link_status, stats.rx_ping_packets), ICMAP_VALUETYPE_UINT64},
  117. { STAT_KNET, "tx_ping_bytes", offsetof(struct knet_link_status, stats.tx_ping_bytes), ICMAP_VALUETYPE_UINT64},
  118. { STAT_KNET, "rx_ping_bytes", offsetof(struct knet_link_status, stats.rx_ping_bytes), ICMAP_VALUETYPE_UINT64},
  119. { STAT_KNET, "tx_pong_packets", offsetof(struct knet_link_status, stats.tx_pong_packets), ICMAP_VALUETYPE_UINT64},
  120. { STAT_KNET, "rx_pong_packets", offsetof(struct knet_link_status, stats.rx_pong_packets), ICMAP_VALUETYPE_UINT64},
  121. { STAT_KNET, "tx_pong_bytes", offsetof(struct knet_link_status, stats.tx_pong_bytes), ICMAP_VALUETYPE_UINT64},
  122. { STAT_KNET, "rx_pong_bytes", offsetof(struct knet_link_status, stats.rx_pong_bytes), ICMAP_VALUETYPE_UINT64},
  123. { STAT_KNET, "tx_pmtu_packets", offsetof(struct knet_link_status, stats.tx_pmtu_packets), ICMAP_VALUETYPE_UINT64},
  124. { STAT_KNET, "rx_pmtu_packets", offsetof(struct knet_link_status, stats.rx_pmtu_packets), ICMAP_VALUETYPE_UINT64},
  125. { STAT_KNET, "tx_pmtu_bytes", offsetof(struct knet_link_status, stats.tx_pmtu_bytes), ICMAP_VALUETYPE_UINT64},
  126. { STAT_KNET, "rx_pmtu_bytes", offsetof(struct knet_link_status, stats.rx_pmtu_bytes), ICMAP_VALUETYPE_UINT64},
  127. { STAT_KNET, "tx_total_packets", offsetof(struct knet_link_status, stats.tx_total_packets), ICMAP_VALUETYPE_UINT64},
  128. { STAT_KNET, "rx_total_packets", offsetof(struct knet_link_status, stats.rx_total_packets), ICMAP_VALUETYPE_UINT64},
  129. { STAT_KNET, "tx_total_bytes", offsetof(struct knet_link_status, stats.tx_total_bytes), ICMAP_VALUETYPE_UINT64},
  130. { STAT_KNET, "rx_total_bytes", offsetof(struct knet_link_status, stats.rx_total_bytes), ICMAP_VALUETYPE_UINT64},
  131. { STAT_KNET, "tx_total_errors", offsetof(struct knet_link_status, stats.tx_total_errors), ICMAP_VALUETYPE_UINT64},
  132. { STAT_KNET, "rx_total_retries", offsetof(struct knet_link_status, stats.tx_total_retries), ICMAP_VALUETYPE_UINT64},
  133. { STAT_KNET, "tx_pmtu_errors", offsetof(struct knet_link_status, stats.tx_pmtu_errors), ICMAP_VALUETYPE_UINT32},
  134. { STAT_KNET, "tx_pmtu_retries", offsetof(struct knet_link_status, stats.tx_pmtu_retries), ICMAP_VALUETYPE_UINT32},
  135. { STAT_KNET, "tx_ping_errors", offsetof(struct knet_link_status, stats.tx_ping_errors), ICMAP_VALUETYPE_UINT32},
  136. { STAT_KNET, "tx_ping_retries", offsetof(struct knet_link_status, stats.tx_ping_retries), ICMAP_VALUETYPE_UINT32},
  137. { STAT_KNET, "tx_pong_errors", offsetof(struct knet_link_status, stats.tx_pong_errors), ICMAP_VALUETYPE_UINT32},
  138. { STAT_KNET, "tx_pong_retries", offsetof(struct knet_link_status, stats.tx_pong_retries), ICMAP_VALUETYPE_UINT32},
  139. { STAT_KNET, "tx_data_errors", offsetof(struct knet_link_status, stats.tx_data_errors), ICMAP_VALUETYPE_UINT32},
  140. { STAT_KNET, "tx_data_retries", offsetof(struct knet_link_status, stats.tx_data_retries), ICMAP_VALUETYPE_UINT32},
  141. { STAT_KNET, "latency_min", offsetof(struct knet_link_status, stats.latency_min), ICMAP_VALUETYPE_UINT32},
  142. { STAT_KNET, "latency_max", offsetof(struct knet_link_status, stats.latency_max), ICMAP_VALUETYPE_UINT32},
  143. { STAT_KNET, "latency_ave", offsetof(struct knet_link_status, stats.latency_ave), ICMAP_VALUETYPE_UINT32},
  144. { STAT_KNET, "latency_samples", offsetof(struct knet_link_status, stats.latency_samples), ICMAP_VALUETYPE_UINT32},
  145. { STAT_KNET, "down_count", offsetof(struct knet_link_status, stats.down_count), ICMAP_VALUETYPE_UINT32},
  146. { STAT_KNET, "up_count", offsetof(struct knet_link_status, stats.up_count), ICMAP_VALUETYPE_UINT32},
  147. };
  148. struct cs_stats_conv cs_knet_handle_stats[] = {
  149. { STAT_KNET_HANDLE, "tx_uncompressed_packets", offsetof(struct knet_handle_stats, tx_uncompressed_packets), ICMAP_VALUETYPE_UINT64},
  150. { STAT_KNET_HANDLE, "tx_compressed_packets", offsetof(struct knet_handle_stats, tx_compressed_packets), ICMAP_VALUETYPE_UINT64},
  151. { STAT_KNET_HANDLE, "tx_compressed_original_bytes", offsetof(struct knet_handle_stats, tx_compressed_original_bytes), ICMAP_VALUETYPE_UINT64},
  152. { STAT_KNET_HANDLE, "tx_compressed_size_bytes", offsetof(struct knet_handle_stats, tx_compressed_size_bytes), ICMAP_VALUETYPE_UINT64},
  153. { STAT_KNET_HANDLE, "tx_compress_time_min", offsetof(struct knet_handle_stats, tx_compress_time_min), ICMAP_VALUETYPE_UINT64},
  154. { STAT_KNET_HANDLE, "tx_compress_time_max", offsetof(struct knet_handle_stats, tx_compress_time_max), ICMAP_VALUETYPE_UINT64},
  155. { STAT_KNET_HANDLE, "tx_compress_time_ave", offsetof(struct knet_handle_stats, tx_compress_time_ave), ICMAP_VALUETYPE_UINT64},
  156. { STAT_KNET_HANDLE, "rx_compressed_packets", offsetof(struct knet_handle_stats, rx_compressed_packets), ICMAP_VALUETYPE_UINT64},
  157. { STAT_KNET_HANDLE, "rx_compressed_original_bytes", offsetof(struct knet_handle_stats, rx_compressed_original_bytes), ICMAP_VALUETYPE_UINT64},
  158. { STAT_KNET_HANDLE, "rx_compressed_size_bytes", offsetof(struct knet_handle_stats, rx_compressed_size_bytes), ICMAP_VALUETYPE_UINT64},
  159. { STAT_KNET_HANDLE, "rx_compress_time_min", offsetof(struct knet_handle_stats, rx_compress_time_min), ICMAP_VALUETYPE_UINT64},
  160. { STAT_KNET_HANDLE, "rx_compress_time_max", offsetof(struct knet_handle_stats, rx_compress_time_max), ICMAP_VALUETYPE_UINT64},
  161. { STAT_KNET_HANDLE, "rx_compress_time_ave", offsetof(struct knet_handle_stats, rx_compress_time_ave), ICMAP_VALUETYPE_UINT64},
  162. { STAT_KNET_HANDLE, "tx_crypt_time_min", offsetof(struct knet_handle_stats, tx_crypt_time_min), ICMAP_VALUETYPE_UINT64},
  163. { STAT_KNET_HANDLE, "tx_crypt_time_max", offsetof(struct knet_handle_stats, tx_crypt_time_max), ICMAP_VALUETYPE_UINT64},
  164. { STAT_KNET_HANDLE, "tx_crypt_time_ave", offsetof(struct knet_handle_stats, tx_crypt_time_ave), ICMAP_VALUETYPE_UINT64},
  165. { STAT_KNET_HANDLE, "tx_crypt_byte_overhead", offsetof(struct knet_handle_stats, tx_crypt_byte_overhead), ICMAP_VALUETYPE_UINT64},
  166. { STAT_KNET_HANDLE, "tx_crypt_packets", offsetof(struct knet_handle_stats, tx_crypt_packets), ICMAP_VALUETYPE_UINT64},
  167. { STAT_KNET_HANDLE, "rx_crypt_time_min", offsetof(struct knet_handle_stats, rx_crypt_time_min), ICMAP_VALUETYPE_UINT64},
  168. { STAT_KNET_HANDLE, "rx_crypt_time_max", offsetof(struct knet_handle_stats, rx_crypt_time_max), ICMAP_VALUETYPE_UINT64},
  169. { STAT_KNET_HANDLE, "rx_crypt_time_ave", offsetof(struct knet_handle_stats, rx_crypt_time_ave), ICMAP_VALUETYPE_UINT64},
  170. { STAT_KNET_HANDLE, "rx_crypt_packets", offsetof(struct knet_handle_stats, rx_crypt_packets), ICMAP_VALUETYPE_UINT64},
  171. };
  172. struct cs_stats_conv cs_ipcs_conn_stats[] = {
  173. { STAT_IPCSC, "queueing", offsetof(struct ipcs_conn_stats, cnx.queuing), ICMAP_VALUETYPE_INT32},
  174. { STAT_IPCSC, "queued", offsetof(struct ipcs_conn_stats, cnx.queued), ICMAP_VALUETYPE_UINT32},
  175. { STAT_IPCSC, "invalid_request", offsetof(struct ipcs_conn_stats, cnx.invalid_request), ICMAP_VALUETYPE_UINT64},
  176. { STAT_IPCSC, "overload", offsetof(struct ipcs_conn_stats, cnx.overload), ICMAP_VALUETYPE_UINT64},
  177. { STAT_IPCSC, "sent", offsetof(struct ipcs_conn_stats, cnx.sent), ICMAP_VALUETYPE_UINT32},
  178. { STAT_IPCSC, "procname", offsetof(struct ipcs_conn_stats, cnx.proc_name), ICMAP_VALUETYPE_STRING},
  179. { STAT_IPCSC, "requests", offsetof(struct ipcs_conn_stats, conn.requests), ICMAP_VALUETYPE_UINT64},
  180. { STAT_IPCSC, "responses", offsetof(struct ipcs_conn_stats, conn.responses), ICMAP_VALUETYPE_UINT64},
  181. { STAT_IPCSC, "dispatched", offsetof(struct ipcs_conn_stats, conn.events), ICMAP_VALUETYPE_UINT64},
  182. { STAT_IPCSC, "send_retries", offsetof(struct ipcs_conn_stats, conn.send_retries), ICMAP_VALUETYPE_UINT64},
  183. { STAT_IPCSC, "recv_retries", offsetof(struct ipcs_conn_stats, conn.recv_retries), ICMAP_VALUETYPE_UINT64},
  184. { STAT_IPCSC, "flow_control", offsetof(struct ipcs_conn_stats, conn.flow_control_state), ICMAP_VALUETYPE_UINT32},
  185. { STAT_IPCSC, "flow_control_count", offsetof(struct ipcs_conn_stats, conn.flow_control_count), ICMAP_VALUETYPE_UINT64},
  186. };
  187. struct cs_stats_conv cs_ipcs_global_stats[] = {
  188. { STAT_IPCSG, "global.active", offsetof(struct ipcs_global_stats, active), ICMAP_VALUETYPE_UINT64},
  189. { STAT_IPCSG, "global.closed", offsetof(struct ipcs_global_stats, closed), ICMAP_VALUETYPE_UINT64},
  190. };
  191. struct cs_stats_conv cs_schedmiss_stats[] = {
  192. { STAT_SCHEDMISS, "timestamp", offsetof(struct schedmiss_entry, timestamp), ICMAP_VALUETYPE_UINT64},
  193. { STAT_SCHEDMISS, "delay", offsetof(struct schedmiss_entry, delay), ICMAP_VALUETYPE_FLOAT},
  194. };
  195. #define NUM_PG_STATS (sizeof(cs_pg_stats) / sizeof(struct cs_stats_conv))
  196. #define NUM_SRP_STATS (sizeof(cs_srp_stats) / sizeof(struct cs_stats_conv))
  197. #define NUM_KNET_STATS (sizeof(cs_knet_stats) / sizeof(struct cs_stats_conv))
  198. #define NUM_KNET_HANDLE_STATS (sizeof(cs_knet_handle_stats) / sizeof(struct cs_stats_conv))
  199. #define NUM_IPCSC_STATS (sizeof(cs_ipcs_conn_stats) / sizeof(struct cs_stats_conv))
  200. #define NUM_IPCSG_STATS (sizeof(cs_ipcs_global_stats) / sizeof(struct cs_stats_conv))
  201. /* What goes in the trie */
  202. struct stats_item {
  203. char *key_name;
  204. struct cs_stats_conv * cs_conv;
  205. };
  206. /* One of these per tracker */
  207. struct cs_stats_tracker
  208. {
  209. char *key_name;
  210. void *user_data;
  211. int32_t events;
  212. icmap_notify_fn_t notify_fn;
  213. uint64_t old_value;
  214. struct qb_list_head list;
  215. };
  216. QB_LIST_DECLARE (stats_tracker_list_head);
  217. static const struct corosync_api_v1 *api;
  218. static void stats_map_set_value(struct cs_stats_conv *conv,
  219. void *stat_array,
  220. void *value,
  221. size_t *value_len,
  222. icmap_value_types_t *type)
  223. {
  224. if (value_len) {
  225. *value_len = icmap_get_valuetype_len(conv->value_type);
  226. }
  227. if (type) {
  228. *type = conv->value_type;
  229. if ((*type == ICMAP_VALUETYPE_STRING) && value_len && stat_array) {
  230. *value_len = strlen((char *)(stat_array) + conv->offset)+1;
  231. }
  232. }
  233. if (value) {
  234. assert(value_len != NULL);
  235. memcpy(value, (char *)(stat_array) + conv->offset, *value_len);
  236. }
  237. }
  238. static void stats_add_entry(const char *key, struct cs_stats_conv *cs_conv)
  239. {
  240. struct stats_item *item = malloc(sizeof(struct stats_item));
  241. if (item) {
  242. item->cs_conv = cs_conv;
  243. item->key_name = strdup(key);
  244. qb_map_put(stats_map, item->key_name, item);
  245. }
  246. }
  247. static void stats_rm_entry(const char *key)
  248. {
  249. struct stats_item *item = qb_map_get(stats_map, key);
  250. if (item) {
  251. qb_map_rm(stats_map, item->key_name);
  252. /* Structures freed in callback below */
  253. }
  254. }
  255. static void stats_map_free_cb(uint32_t event,
  256. char* key, void* old_value,
  257. void* value, void* user_data)
  258. {
  259. struct stats_item *item = (struct stats_item *)old_value;
  260. if (item) {
  261. free(item->key_name);
  262. free(item);
  263. }
  264. }
  265. cs_error_t stats_map_init(const struct corosync_api_v1 *corosync_api)
  266. {
  267. int i;
  268. char param[ICMAP_KEYNAME_MAXLEN];
  269. int32_t err;
  270. api = corosync_api;
  271. stats_map = qb_trie_create();
  272. if (!stats_map) {
  273. return CS_ERR_INIT;
  274. }
  275. /* Populate the static portions of the trie */
  276. for (i = 0; i<NUM_PG_STATS; i++) {
  277. sprintf(param, "stats.pg.%s", cs_pg_stats[i].name);
  278. stats_add_entry(param, &cs_pg_stats[i]);
  279. }
  280. for (i = 0; i<NUM_SRP_STATS; i++) {
  281. sprintf(param, "stats.srp.%s", cs_srp_stats[i].name);
  282. stats_add_entry(param, &cs_srp_stats[i]);
  283. }
  284. for (i = 0; i<NUM_IPCSG_STATS; i++) {
  285. sprintf(param, "stats.ipcs.%s", cs_ipcs_global_stats[i].name);
  286. stats_add_entry(param, &cs_ipcs_global_stats[i]);
  287. }
  288. /* KNET, IPCS & SCHEDMISS stats are added when appropriate */
  289. /* Call us when we can free things */
  290. err = qb_map_notify_add(stats_map, NULL, stats_map_free_cb, QB_MAP_NOTIFY_FREE, NULL);
  291. return (qb_to_cs_error(err));
  292. }
  293. cs_error_t stats_map_get(const char *key_name,
  294. void *value,
  295. size_t *value_len,
  296. icmap_value_types_t *type)
  297. {
  298. struct cs_stats_conv *statinfo;
  299. struct stats_item *item;
  300. totempg_stats_t *pg_stats;
  301. struct knet_link_status link_status;
  302. struct ipcs_conn_stats ipcs_conn_stats;
  303. struct ipcs_global_stats ipcs_global_stats;
  304. struct knet_handle_stats knet_handle_stats;
  305. int res;
  306. int nodeid;
  307. int link_no;
  308. int service_id;
  309. uint32_t pid;
  310. unsigned int sm_event;
  311. char *sm_type;
  312. void *conn_ptr;
  313. item = qb_map_get(stats_map, key_name);
  314. if (!item) {
  315. return CS_ERR_NOT_EXIST;
  316. }
  317. statinfo = item->cs_conv;
  318. switch (statinfo->type) {
  319. case STAT_PG:
  320. pg_stats = api->totem_get_stats();
  321. stats_map_set_value(statinfo, pg_stats, value, value_len, type);
  322. break;
  323. case STAT_SRP:
  324. pg_stats = api->totem_get_stats();
  325. stats_map_set_value(statinfo, pg_stats->srp, value, value_len, type);
  326. break;
  327. case STAT_KNET_HANDLE:
  328. res = totemknet_handle_get_stats(&knet_handle_stats);
  329. if (res != CS_OK) {
  330. return res;
  331. }
  332. stats_map_set_value(statinfo, &knet_handle_stats, value, value_len, type);
  333. break;
  334. case STAT_KNET:
  335. if (sscanf(key_name, "stats.knet.node%d.link%d", &nodeid, &link_no) != 2) {
  336. return CS_ERR_NOT_EXIST;
  337. }
  338. /* Validate node & link IDs */
  339. if (nodeid <= 0 || nodeid > KNET_MAX_HOST ||
  340. link_no < 0 || link_no > KNET_MAX_LINK) {
  341. return CS_ERR_NOT_EXIST;
  342. }
  343. /* Always get the latest stats */
  344. res = totemknet_link_get_status((knet_node_id_t)nodeid, (uint8_t)link_no, &link_status);
  345. if (res != CS_OK) {
  346. return CS_ERR_LIBRARY;
  347. }
  348. stats_map_set_value(statinfo, &link_status, value, value_len, type);
  349. break;
  350. case STAT_IPCSC:
  351. if (sscanf(key_name, "stats.ipcs.service%d.%d.%p", &service_id, &pid, &conn_ptr) != 3) {
  352. return CS_ERR_NOT_EXIST;
  353. }
  354. res = cs_ipcs_get_conn_stats(service_id, pid, conn_ptr, &ipcs_conn_stats);
  355. if (res != CS_OK) {
  356. return res;
  357. }
  358. stats_map_set_value(statinfo, &ipcs_conn_stats, value, value_len, type);
  359. break;
  360. case STAT_IPCSG:
  361. cs_ipcs_get_global_stats(&ipcs_global_stats);
  362. stats_map_set_value(statinfo, &ipcs_global_stats, value, value_len, type);
  363. break;
  364. case STAT_SCHEDMISS:
  365. if (sscanf(key_name, SCHEDMISS_PREFIX ".%d", &sm_event) != 1) {
  366. return CS_ERR_NOT_EXIST;
  367. }
  368. sm_type = strrchr(key_name, '.');
  369. if (sm_type == NULL) {
  370. return CS_ERR_NOT_EXIST;
  371. }
  372. sm_type++;
  373. if (strcmp(sm_type, "timestamp") == 0) {
  374. memcpy(value, &schedmiss_event[sm_event].timestamp, sizeof(uint64_t));
  375. *value_len = sizeof(uint64_t);
  376. *type = ICMAP_VALUETYPE_UINT64;
  377. }
  378. if (strcmp(sm_type, "delay") == 0) {
  379. memcpy(value, &schedmiss_event[sm_event].delay, sizeof(float));
  380. *value_len = sizeof(float);
  381. *type = ICMAP_VALUETYPE_FLOAT;
  382. }
  383. break;
  384. default:
  385. return CS_ERR_LIBRARY;
  386. }
  387. return CS_OK;
  388. }
  389. static void schedmiss_clear_stats(void)
  390. {
  391. int i;
  392. char param[ICMAP_KEYNAME_MAXLEN];
  393. for (i=0; i<MAX_SCHEDMISS_EVENTS; i++) {
  394. if (i < highest_schedmiss_event) {
  395. sprintf(param, SCHEDMISS_PREFIX ".%i.timestamp", i);
  396. stats_rm_entry(param);
  397. sprintf(param, SCHEDMISS_PREFIX ".%i.delay", i);
  398. stats_rm_entry(param);
  399. }
  400. schedmiss_event[i].timestamp = (uint64_t)0LL;
  401. schedmiss_event[i].delay = 0.0f;
  402. }
  403. highest_schedmiss_event = 0;
  404. }
  405. /* Called from main.c */
  406. void stats_add_schedmiss_event(uint64_t timestamp, float delay)
  407. {
  408. char param[ICMAP_KEYNAME_MAXLEN];
  409. int i;
  410. /* Move 'em all up */
  411. for (i=MAX_SCHEDMISS_EVENTS-2; i>=0; i--) {
  412. schedmiss_event[i+1].timestamp = schedmiss_event[i].timestamp;
  413. schedmiss_event[i+1].delay = schedmiss_event[i].delay;
  414. }
  415. /* New entries are always at the front */
  416. schedmiss_event[0].timestamp = timestamp;
  417. schedmiss_event[0].delay = delay;
  418. /* If we've not run off the end then add an entry in the trie for the new 'end' one */
  419. if (highest_schedmiss_event < MAX_SCHEDMISS_EVENTS) {
  420. sprintf(param, SCHEDMISS_PREFIX ".%i.timestamp", highest_schedmiss_event);
  421. stats_add_entry(param, &cs_schedmiss_stats[0]);
  422. sprintf(param, SCHEDMISS_PREFIX ".%i.delay", highest_schedmiss_event);
  423. stats_add_entry(param, &cs_schedmiss_stats[1]);
  424. highest_schedmiss_event++;
  425. }
  426. /* Notifications get sent by the stats_updater */
  427. }
  428. #define STATS_CLEAR "stats.clear."
  429. #define STATS_CLEAR_KNET "stats.clear.knet"
  430. #define STATS_CLEAR_IPC "stats.clear.ipc"
  431. #define STATS_CLEAR_TOTEM "stats.clear.totem"
  432. #define STATS_CLEAR_ALL "stats.clear.all"
  433. #define STATS_CLEAR_SCHEDMISS "stats.clear.schedmiss"
  434. cs_error_t stats_map_set(const char *key_name,
  435. const void *value,
  436. size_t value_len,
  437. icmap_value_types_t type)
  438. {
  439. int cleared = 0;
  440. if (strncmp(key_name, STATS_CLEAR_KNET, strlen(STATS_CLEAR_KNET)) == 0) {
  441. totempg_stats_clear(TOTEMPG_STATS_CLEAR_TRANSPORT);
  442. cleared = 1;
  443. }
  444. if (strncmp(key_name, STATS_CLEAR_IPC, strlen(STATS_CLEAR_IPC)) == 0) {
  445. cs_ipcs_clear_stats();
  446. cleared = 1;
  447. }
  448. if (strncmp(key_name, STATS_CLEAR_TOTEM, strlen(STATS_CLEAR_TOTEM)) == 0) {
  449. totempg_stats_clear(TOTEMPG_STATS_CLEAR_TOTEM);
  450. cleared = 1;
  451. }
  452. if (strncmp(key_name, STATS_CLEAR_SCHEDMISS, strlen(STATS_CLEAR_SCHEDMISS)) == 0) {
  453. schedmiss_clear_stats();
  454. cleared = 1;
  455. }
  456. if (strncmp(key_name, STATS_CLEAR_ALL, strlen(STATS_CLEAR_ALL)) == 0) {
  457. totempg_stats_clear(TOTEMPG_STATS_CLEAR_TRANSPORT | TOTEMPG_STATS_CLEAR_TOTEM);
  458. cs_ipcs_clear_stats();
  459. schedmiss_clear_stats();
  460. cleared = 1;
  461. }
  462. if (!cleared) {
  463. return CS_ERR_NOT_SUPPORTED;
  464. }
  465. return CS_OK;
  466. }
  467. cs_error_t stats_map_adjust_int(const char *key_name, int32_t step)
  468. {
  469. return CS_ERR_NOT_SUPPORTED;
  470. }
  471. cs_error_t stats_map_delete(const char *key_name)
  472. {
  473. return CS_ERR_NOT_SUPPORTED;
  474. }
  475. int stats_map_is_key_ro(const char *key_name)
  476. {
  477. /* It's all read-only apart from the 'clear' destinations */
  478. if (strncmp(key_name, STATS_CLEAR, strlen(STATS_CLEAR)) == 0) {
  479. return 0;
  480. } else {
  481. return 1;
  482. }
  483. }
  484. icmap_iter_t stats_map_iter_init(const char *prefix)
  485. {
  486. return (qb_map_pref_iter_create(stats_map, prefix));
  487. }
  488. const char *stats_map_iter_next(icmap_iter_t iter, size_t *value_len, icmap_value_types_t *type)
  489. {
  490. const char *res;
  491. struct stats_item *item;
  492. res = qb_map_iter_next(iter, (void **)&item);
  493. if (res == NULL) {
  494. return (res);
  495. }
  496. stats_map_set_value(item->cs_conv, NULL, NULL, value_len, type);
  497. return res;
  498. }
  499. void stats_map_iter_finalize(icmap_iter_t iter)
  500. {
  501. qb_map_iter_free(iter);
  502. }
  503. void stats_trigger_trackers()
  504. {
  505. struct cs_stats_tracker *tracker;
  506. struct qb_list_head *iter;
  507. cs_error_t res;
  508. size_t value_len;
  509. icmap_value_types_t type;
  510. uint64_t value;
  511. struct icmap_notify_value new_val;
  512. struct icmap_notify_value old_val;
  513. qb_list_for_each(iter, &stats_tracker_list_head) {
  514. tracker = qb_list_entry(iter, struct cs_stats_tracker, list);
  515. if (tracker->events & ICMAP_TRACK_PREFIX || !tracker->key_name ) {
  516. continue;
  517. }
  518. res = stats_map_get(tracker->key_name,
  519. &value, &value_len, &type);
  520. /* Check if it has changed */
  521. if ((res == CS_OK) && (memcmp(&value, &tracker->old_value, value_len) != 0)) {
  522. old_val.type = new_val.type = type;
  523. old_val.len = new_val.len = value_len;
  524. old_val.data = new_val.data = &value;
  525. tracker->notify_fn(ICMAP_TRACK_MODIFY, tracker->key_name,
  526. old_val, new_val, tracker->user_data);
  527. memcpy(&tracker->old_value, &value, value_len);
  528. }
  529. }
  530. }
  531. /* Callback from libqb when a key is added/removed */
  532. static void stats_map_notify_fn(uint32_t event, char *key, void *old_value, void *value, void *user_data)
  533. {
  534. struct cs_stats_tracker *tracker = user_data;
  535. struct icmap_notify_value new_val;
  536. struct icmap_notify_value old_val;
  537. char new_value[64];
  538. if (value == NULL && old_value == NULL) {
  539. return ;
  540. }
  541. /* Ignore schedmiss trackers as the values are read from the circular buffer */
  542. if (strncmp(key, SCHEDMISS_PREFIX, strlen(SCHEDMISS_PREFIX)) == 0 ) {
  543. return ;
  544. }
  545. new_val.data = new_value;
  546. if (stats_map_get(key,
  547. &new_value,
  548. &new_val.len,
  549. &new_val.type) != CS_OK) {
  550. log_printf(LOGSYS_LEVEL_WARNING, "get value of notified key %s failed", key);
  551. return ;
  552. }
  553. /* We don't know what the old value was
  554. but as this only tracks ADD & DELETE I'm not worried
  555. about it */
  556. memcpy(&old_val, &new_val, sizeof(new_val));
  557. tracker->notify_fn(icmap_qbtt_to_tt(event),
  558. key,
  559. new_val,
  560. old_val,
  561. tracker->user_data);
  562. }
  563. cs_error_t stats_map_track_add(const char *key_name,
  564. int32_t track_type,
  565. icmap_notify_fn_t notify_fn,
  566. void *user_data,
  567. icmap_track_t *icmap_track)
  568. {
  569. struct cs_stats_tracker *tracker;
  570. size_t value_len;
  571. icmap_value_types_t type;
  572. cs_error_t err;
  573. /* We can track adding or deleting a key under a prefix */
  574. if ((track_type & ICMAP_TRACK_PREFIX) &&
  575. (!(track_type & ICMAP_TRACK_DELETE) ||
  576. !(track_type & ICMAP_TRACK_ADD))) {
  577. return CS_ERR_NOT_SUPPORTED;
  578. }
  579. tracker = malloc(sizeof(struct cs_stats_tracker));
  580. if (!tracker) {
  581. return CS_ERR_NO_MEMORY;
  582. }
  583. tracker->notify_fn = notify_fn;
  584. tracker->user_data = user_data;
  585. tracker->events = track_type;
  586. if (key_name) {
  587. tracker->key_name = strdup(key_name);
  588. if (!tracker->key_name) {
  589. free(tracker);
  590. return CS_ERR_NO_MEMORY;
  591. }
  592. /* Get initial value */
  593. if (stats_map_get(tracker->key_name,
  594. &tracker->old_value, &value_len, &type) != CS_OK) {
  595. tracker->old_value = 0ULL;
  596. }
  597. } else {
  598. tracker->key_name = NULL;
  599. tracker->old_value = 0ULL;
  600. }
  601. /* Add/delete trackers can use the qb_map tracking */
  602. if ((track_type & ICMAP_TRACK_ADD) ||
  603. (track_type & ICMAP_TRACK_DELETE)) {
  604. err = qb_map_notify_add(stats_map, tracker->key_name,
  605. stats_map_notify_fn,
  606. icmap_tt_to_qbtt(track_type),
  607. tracker);
  608. if (err != 0) {
  609. log_printf(LOGSYS_LEVEL_ERROR, "creating stats tracker %s failed. %d\n", tracker->key_name, err);
  610. free(tracker->key_name);
  611. free(tracker);
  612. return (qb_to_cs_error(err));
  613. }
  614. }
  615. qb_list_add (&tracker->list, &stats_tracker_list_head);
  616. *icmap_track = (icmap_track_t)tracker;
  617. return CS_OK;
  618. }
  619. cs_error_t stats_map_track_delete(icmap_track_t icmap_track)
  620. {
  621. struct cs_stats_tracker *tracker = (struct cs_stats_tracker *)icmap_track;
  622. int err;
  623. if ((tracker->events & ICMAP_TRACK_ADD) ||
  624. (tracker->events & ICMAP_TRACK_DELETE)) {
  625. err = qb_map_notify_del_2(stats_map,
  626. tracker->key_name, stats_map_notify_fn,
  627. icmap_tt_to_qbtt(tracker->events), tracker);
  628. if (err) {
  629. log_printf(LOGSYS_LEVEL_ERROR, "deleting tracker %s failed. %d\n", tracker->key_name, err);
  630. }
  631. }
  632. qb_list_del(&tracker->list);
  633. free(tracker->key_name);
  634. free(tracker);
  635. return CS_OK;
  636. }
  637. void *stats_map_track_get_user_data(icmap_track_t icmap_track)
  638. {
  639. struct cs_stats_tracker *tracker = (struct cs_stats_tracker *)icmap_track;
  640. return tracker->user_data;
  641. }
  642. /* Called from totemknet to add/remove keys from our map */
  643. void stats_knet_add_member(knet_node_id_t nodeid, uint8_t link_no)
  644. {
  645. int i;
  646. char param[ICMAP_KEYNAME_MAXLEN];
  647. for (i = 0; i<NUM_KNET_STATS; i++) {
  648. sprintf(param, "stats.knet.node%d.link%d.%s", nodeid, link_no, cs_knet_stats[i].name);
  649. stats_add_entry(param, &cs_knet_stats[i]);
  650. }
  651. }
  652. void stats_knet_del_member(knet_node_id_t nodeid, uint8_t link_no)
  653. {
  654. int i;
  655. char param[ICMAP_KEYNAME_MAXLEN];
  656. for (i = 0; i<NUM_KNET_STATS; i++) {
  657. sprintf(param, "stats.knet.node%d.link%d.%s", nodeid, link_no, cs_knet_stats[i].name);
  658. stats_rm_entry(param);
  659. }
  660. }
  661. /* This is separated out from stats_map_init() because we don't know whether
  662. knet is in use until much later in the startup */
  663. void stats_knet_add_handle(void)
  664. {
  665. int i;
  666. char param[ICMAP_KEYNAME_MAXLEN];
  667. for (i = 0; i<NUM_KNET_HANDLE_STATS; i++) {
  668. sprintf(param, "stats.knet.handle.%s", cs_knet_handle_stats[i].name);
  669. stats_add_entry(param, &cs_knet_handle_stats[i]);
  670. }
  671. }
  672. /* Called from ipc_glue to add/remove keys from our map */
  673. void stats_ipcs_add_connection(int service_id, uint32_t pid, void *ptr)
  674. {
  675. int i;
  676. char param[ICMAP_KEYNAME_MAXLEN];
  677. for (i = 0; i<NUM_IPCSC_STATS; i++) {
  678. sprintf(param, "stats.ipcs.service%d.%d.%p.%s", service_id, pid, ptr, cs_ipcs_conn_stats[i].name);
  679. stats_add_entry(param, &cs_ipcs_conn_stats[i]);
  680. }
  681. }
  682. void stats_ipcs_del_connection(int service_id, uint32_t pid, void *ptr)
  683. {
  684. int i;
  685. char param[ICMAP_KEYNAME_MAXLEN];
  686. for (i = 0; i<NUM_IPCSC_STATS; i++) {
  687. sprintf(param, "stats.ipcs.service%d.%d.%p.%s", service_id, pid, ptr, cs_ipcs_conn_stats[i].name);
  688. stats_rm_entry(param);
  689. }
  690. }