Metric.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. htop - Metric.c
  3. (C) 2020-2021 htop dev team
  4. (C) 2020-2021 Red Hat, Inc.
  5. Released under the GNU GPLv2+, see the COPYING file
  6. in the source distribution for its full text.
  7. */
  8. #include "config.h" // IWYU pragma: keep
  9. #include "pcp/Metric.h"
  10. #include <ctype.h>
  11. #include <stddef.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include "XUtils.h"
  15. #include "pcp/Platform.h"
  16. extern Platform* pcp;
  17. const pmDesc* Metric_desc(Metric metric) {
  18. return &pcp->descs[metric];
  19. }
  20. int Metric_type(Metric metric) {
  21. return pcp->descs[metric].type;
  22. }
  23. pmAtomValue* Metric_values(Metric metric, pmAtomValue* atom, int count, int type) {
  24. if (pcp->result == NULL)
  25. return NULL;
  26. pmValueSet* vset = pcp->result->vset[metric];
  27. if (!vset || vset->numval <= 0)
  28. return NULL;
  29. /* extract requested number of values as requested type */
  30. const pmDesc* desc = &pcp->descs[metric];
  31. for (int i = 0; i < vset->numval; i++) {
  32. if (i == count)
  33. break;
  34. const pmValue* value = &vset->vlist[i];
  35. int sts = pmExtractValue(vset->valfmt, value, desc->type, &atom[i], type);
  36. if (sts < 0) {
  37. if (pmDebugOptions.appl0)
  38. fprintf(stderr, "Error: cannot extract metric value: %s\n",
  39. pmErrStr(sts));
  40. memset(&atom[i], 0, sizeof(pmAtomValue));
  41. }
  42. }
  43. return atom;
  44. }
  45. int Metric_instanceCount(Metric metric) {
  46. pmValueSet* vset = pcp->result->vset[metric];
  47. if (vset)
  48. return vset->numval;
  49. return 0;
  50. }
  51. int Metric_instanceOffset(Metric metric, int inst) {
  52. pmValueSet* vset = pcp->result->vset[metric];
  53. if (!vset || vset->numval <= 0)
  54. return 0;
  55. /* search for optimal offset for subsequent inst lookups to begin */
  56. for (int i = 0; i < vset->numval; i++) {
  57. if (inst == vset->vlist[i].inst)
  58. return i;
  59. }
  60. return 0;
  61. }
  62. static pmAtomValue* Metric_extract(Metric metric, int inst, int offset, pmValueSet* vset, pmAtomValue* atom, int type) {
  63. /* extract value (using requested type) of given metric instance */
  64. const pmDesc* desc = &pcp->descs[metric];
  65. const pmValue* value = &vset->vlist[offset];
  66. int sts = pmExtractValue(vset->valfmt, value, desc->type, atom, type);
  67. if (sts < 0) {
  68. if (pmDebugOptions.appl0)
  69. fprintf(stderr, "Error: cannot extract %s instance %d value: %s\n",
  70. pcp->names[metric], inst, pmErrStr(sts));
  71. memset(atom, 0, sizeof(pmAtomValue));
  72. }
  73. return atom;
  74. }
  75. pmAtomValue* Metric_instance(Metric metric, int inst, int offset, pmAtomValue* atom, int type) {
  76. pmValueSet* vset = pcp->result->vset[metric];
  77. if (!vset || vset->numval <= 0)
  78. return NULL;
  79. /* fast-path using heuristic offset based on expected location */
  80. if (offset >= 0 && offset < vset->numval && inst == vset->vlist[offset].inst)
  81. return Metric_extract(metric, inst, offset, vset, atom, type);
  82. /* slow-path using a linear search for the requested instance */
  83. for (int i = 0; i < vset->numval; i++) {
  84. if (inst == vset->vlist[i].inst)
  85. return Metric_extract(metric, inst, i, vset, atom, type);
  86. }
  87. return NULL;
  88. }
  89. /*
  90. * Iterate over a set of instances (incl PM_IN_NULL)
  91. * returning the next instance identifier and offset.
  92. *
  93. * Start it off by passing offset -1 into the routine.
  94. */
  95. bool Metric_iterate(Metric metric, int* instp, int* offsetp) {
  96. if (!pcp->result)
  97. return false;
  98. pmValueSet* vset = pcp->result->vset[metric];
  99. if (!vset || vset->numval <= 0)
  100. return false;
  101. int offset = *offsetp;
  102. offset = (offset < 0) ? 0 : offset + 1;
  103. if (offset > vset->numval - 1)
  104. return false;
  105. *offsetp = offset;
  106. *instp = vset->vlist[offset].inst;
  107. return true;
  108. }
  109. /* Switch on/off a metric for value fetching (sampling) */
  110. void Metric_enable(Metric metric, bool enable) {
  111. pcp->fetch[metric] = enable ? pcp->pmids[metric] : PM_ID_NULL;
  112. }
  113. bool Metric_enabled(Metric metric) {
  114. return pcp->fetch[metric] != PM_ID_NULL;
  115. }
  116. void Metric_enableThreads(void) {
  117. pmValueSet* vset = xCalloc(1, sizeof(pmValueSet));
  118. vset->vlist[0].inst = PM_IN_NULL;
  119. vset->vlist[0].value.lval = 1;
  120. vset->valfmt = PM_VAL_INSITU;
  121. vset->numval = 1;
  122. vset->pmid = pcp->pmids[PCP_CONTROL_THREADS];
  123. pmResult* result = xCalloc(1, sizeof(pmResult));
  124. result->vset[0] = vset;
  125. result->numpmid = 1;
  126. int sts = pmStore(result);
  127. if (sts < 0 && pmDebugOptions.appl0)
  128. fprintf(stderr, "Error: cannot enable threads: %s\n", pmErrStr(sts));
  129. pmFreeResult(result);
  130. }
  131. bool Metric_fetch(struct timeval* timestamp) {
  132. if (pcp->result) {
  133. pmFreeResult(pcp->result);
  134. pcp->result = NULL;
  135. }
  136. int sts, count = 0;
  137. do {
  138. sts = pmFetch(pcp->totalMetrics, pcp->fetch, &pcp->result);
  139. } while (sts == PM_ERR_IPC && ++count < 3);
  140. if (sts < 0) {
  141. if (pmDebugOptions.appl0)
  142. fprintf(stderr, "Error: cannot fetch metric values: %s\n",
  143. pmErrStr(sts));
  144. return false;
  145. }
  146. if (timestamp)
  147. *timestamp = pcp->result->timestamp;
  148. return true;
  149. }
  150. void Metric_externalName(Metric metric, int inst, char** externalName) {
  151. const pmDesc* desc = &pcp->descs[metric];
  152. /* ignore a failure here - its safe to do so */
  153. (void)pmNameInDom(desc->indom, inst, externalName);
  154. }
  155. int Metric_lookupText(const char* metric, char** desc) {
  156. pmID pmid;
  157. int sts;
  158. sts = pmLookupName(1, &metric, &pmid);
  159. if (sts < 0)
  160. return sts;
  161. if (pmLookupText(pmid, PM_TEXT_ONELINE, desc) >= 0)
  162. (*desc)[0] = toupper((*desc)[0]); /* UI consistency */
  163. return 0;
  164. }