123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- // SPDX-License-Identifier: GPL-3.0-or-later
- #include "perflib-rrd.h"
- #define COLLECTED_NUMBER_PRECISION 10000
- RRDDIM *perflib_rrddim_add(RRDSET *st, const char *id, const char *name, collected_number multiplier, collected_number divider, COUNTER_DATA *cd) {
- RRD_ALGORITHM algorithm = RRD_ALGORITHM_ABSOLUTE;
- switch (cd->current.CounterType) {
- case PERF_COUNTER_COUNTER:
- case PERF_SAMPLE_COUNTER:
- case PERF_COUNTER_BULK_COUNT:
- // (N1 - N0) / ((D1 - D0) / F)
- // multiplier *= cd->current.Frequency / 10000000;
- // tested, the frequency is not that useful for netdata
- // we get right results without it.
- algorithm = RRD_ALGORITHM_INCREMENTAL;
- break;
- case PERF_COUNTER_QUEUELEN_TYPE:
- case PERF_COUNTER_100NS_QUEUELEN_TYPE:
- case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
- case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
- case PERF_AVERAGE_BULK: // normally not displayed
- // (N1 - N0) / (D1 - D0)
- algorithm = RRD_ALGORITHM_INCREMENTAL;
- break;
- case PERF_OBJ_TIME_TIMER:
- case PERF_COUNTER_TIMER:
- case PERF_100NSEC_TIMER:
- case PERF_PRECISION_SYSTEM_TIMER:
- case PERF_PRECISION_100NS_TIMER:
- case PERF_PRECISION_OBJECT_TIMER:
- case PERF_SAMPLE_FRACTION:
- // 100 * (N1 - N0) / (D1 - D0)
- multiplier *= 100;
- algorithm = RRD_ALGORITHM_INCREMENTAL;
- break;
- case PERF_COUNTER_TIMER_INV:
- case PERF_100NSEC_TIMER_INV:
- // 100 * (1 - ((N1 - N0) / (D1 - D0)))
- divider *= COLLECTED_NUMBER_PRECISION;
- algorithm = RRD_ALGORITHM_ABSOLUTE;
- break;
- case PERF_COUNTER_MULTI_TIMER:
- // 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
- divider *= COLLECTED_NUMBER_PRECISION;
- algorithm = RRD_ALGORITHM_ABSOLUTE;
- break;
- case PERF_100NSEC_MULTI_TIMER:
- // 100 * ((N1 - N0) / (D1 - D0)) / B1
- divider *= COLLECTED_NUMBER_PRECISION;
- algorithm = RRD_ALGORITHM_ABSOLUTE;
- break;
- case PERF_COUNTER_MULTI_TIMER_INV:
- case PERF_100NSEC_MULTI_TIMER_INV:
- // 100 * (B1 - ((N1 - N0) / (D1 - D0)))
- divider *= COLLECTED_NUMBER_PRECISION;
- algorithm = RRD_ALGORITHM_ABSOLUTE;
- break;
- case PERF_COUNTER_RAWCOUNT:
- case PERF_COUNTER_LARGE_RAWCOUNT:
- // N as decimal
- algorithm = RRD_ALGORITHM_ABSOLUTE;
- break;
- case PERF_COUNTER_RAWCOUNT_HEX:
- case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
- // N as hexadecimal
- algorithm = RRD_ALGORITHM_ABSOLUTE;
- break;
- case PERF_COUNTER_DELTA:
- case PERF_COUNTER_LARGE_DELTA:
- // N1 - N0
- algorithm = RRD_ALGORITHM_ABSOLUTE;
- break;
- case PERF_RAW_FRACTION:
- case PERF_LARGE_RAW_FRACTION:
- // 100 * N / B
- algorithm = RRD_ALGORITHM_ABSOLUTE;
- divider *= COLLECTED_NUMBER_PRECISION;
- break;
- case PERF_AVERAGE_TIMER:
- // ((N1 - N0) / TB) / (B1 - B0)
- // divider *= cd->current.Frequency / 10000000;
- algorithm = RRD_ALGORITHM_INCREMENTAL;
- break;
- case PERF_ELAPSED_TIME:
- // (D0 - N0) / F
- algorithm = RRD_ALGORITHM_ABSOLUTE;
- break;
- case PERF_COUNTER_TEXT:
- case PERF_SAMPLE_BASE:
- case PERF_AVERAGE_BASE:
- case PERF_COUNTER_MULTI_BASE:
- case PERF_RAW_BASE:
- case PERF_COUNTER_NODATA:
- case PERF_PRECISION_TIMESTAMP:
- default:
- break;
- }
- return rrddim_add(st, id, name, multiplier, divider, algorithm);
- }
- #define VALID_DELTA(cd) \
- ((cd)->previous.Time > 0 && (cd)->current.Data >= (cd)->previous.Data && (cd)->current.Time > (cd)->previous.Time)
- collected_number perflib_rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, COUNTER_DATA *cd) {
- ULONGLONG numerator = 0;
- LONGLONG denominator = 0;
- double doubleValue = 0.0;
- collected_number value;
- switch(cd->current.CounterType) {
- case PERF_COUNTER_COUNTER:
- case PERF_SAMPLE_COUNTER:
- case PERF_COUNTER_BULK_COUNT:
- // (N1 - N0) / ((D1 - D0) / F)
- value = (collected_number)cd->current.Data;
- break;
- case PERF_COUNTER_QUEUELEN_TYPE:
- case PERF_COUNTER_100NS_QUEUELEN_TYPE:
- case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
- case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
- case PERF_AVERAGE_BULK: // normally not displayed
- // (N1 - N0) / (D1 - D0)
- value = (collected_number)cd->current.Data;
- break;
- case PERF_OBJ_TIME_TIMER:
- case PERF_COUNTER_TIMER:
- case PERF_100NSEC_TIMER:
- case PERF_PRECISION_SYSTEM_TIMER:
- case PERF_PRECISION_100NS_TIMER:
- case PERF_PRECISION_OBJECT_TIMER:
- case PERF_SAMPLE_FRACTION:
- // 100 * (N1 - N0) / (D1 - D0)
- value = (collected_number)cd->current.Data;
- break;
- case PERF_COUNTER_TIMER_INV:
- case PERF_100NSEC_TIMER_INV:
- // 100 * (1 - ((N1 - N0) / (D1 - D0)))
- if(!VALID_DELTA(cd)) return 0;
- numerator = cd->current.Data - cd->previous.Data;
- denominator = cd->current.Time - cd->previous.Time;
- doubleValue = 100.0 * (1.0 - ((double)numerator / (double)denominator));
- // printf("Display value is (timer-inv): %f%%\n", doubleValue);
- value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
- break;
- case PERF_COUNTER_MULTI_TIMER:
- // 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
- if(!VALID_DELTA(cd)) return 0;
- numerator = cd->current.Data - cd->previous.Data;
- denominator = cd->current.Time - cd->previous.Time;
- denominator /= cd->current.Frequency;
- doubleValue = 100.0 * ((double)numerator / (double)denominator) / cd->current.MultiCounterData;
- // printf("Display value is (multi-timer): %f%%\n", doubleValue);
- value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
- break;
- case PERF_100NSEC_MULTI_TIMER:
- // 100 * ((N1 - N0) / (D1 - D0)) / B1
- if(!VALID_DELTA(cd)) return 0;
- numerator = cd->current.Data - cd->previous.Data;
- denominator = cd->current.Time - cd->previous.Time;
- doubleValue = 100.0 * ((double)numerator / (double)denominator) / (double)cd->current.MultiCounterData;
- // printf("Display value is (100ns multi-timer): %f%%\n", doubleValue);
- value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
- break;
- case PERF_COUNTER_MULTI_TIMER_INV:
- case PERF_100NSEC_MULTI_TIMER_INV:
- // 100 * (B1 - ((N1 - N0) / (D1 - D0)))
- if(!VALID_DELTA(cd)) return 0;
- numerator = cd->current.Data - cd->previous.Data;
- denominator = cd->current.Time - cd->previous.Time;
- doubleValue = 100.0 * ((double)cd->current.MultiCounterData - ((double)numerator / (double)denominator));
- // printf("Display value is (multi-timer-inv): %f%%\n", doubleValue);
- value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
- break;
- case PERF_COUNTER_RAWCOUNT:
- case PERF_COUNTER_LARGE_RAWCOUNT:
- // N as decimal
- value = (collected_number)cd->current.Data;
- break;
- case PERF_COUNTER_RAWCOUNT_HEX:
- case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
- // N as hexadecimal
- value = (collected_number)cd->current.Data;
- break;
- case PERF_COUNTER_DELTA:
- case PERF_COUNTER_LARGE_DELTA:
- if(!VALID_DELTA(cd)) return 0;
- value = (collected_number)(cd->current.Data - cd->previous.Data);
- break;
- case PERF_RAW_FRACTION:
- case PERF_LARGE_RAW_FRACTION:
- // 100 * N / B
- if(!cd->current.Time) return 0;
- doubleValue = 100.0 * (double)cd->current.Data / (double)cd->current.Time;
- // printf("Display value is (fraction): %f%%\n", doubleValue);
- value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
- break;
- default:
- return 0;
- }
- return rrddim_set_by_pointer(st, rd, value);
- }
- /*
- double perflibCalculateValue(RAW_DATA *current, RAW_DATA *previous) {
- ULONGLONG numerator = 0;
- LONGLONG denominator = 0;
- double doubleValue = 0.0;
- DWORD dwordValue = 0;
- if (NULL == previous) {
- // Return error if the counter type requires two samples to calculate the value.
- switch (current->CounterType) {
- default:
- if (PERF_DELTA_COUNTER != (current->CounterType & PERF_DELTA_COUNTER))
- break;
- __fallthrough;
- // fallthrough
- case PERF_AVERAGE_TIMER: // Special case.
- case PERF_AVERAGE_BULK: // Special case.
- // printf(" > The counter type requires two samples but only one sample was provided.\n");
- return NAN;
- }
- }
- else {
- if (current->CounterType != previous->CounterType) {
- // printf(" > The samples have inconsistent counter types.\n");
- return NAN;
- }
- // Check for integer overflow or bad data from provider (the data from
- // sample 2 must be greater than the data from sample 1).
- if (current->Data < previous->Data)
- {
- // Can happen for various reasons. Commonly occurs with the Process counterset when
- // multiple processes have the same name and one of them starts or stops.
- // Normally you'll just drop the older sample and continue.
- // printf("> current (%llu) is smaller than previous (%llu).\n", current->Data, previous->Data);
- return NAN;
- }
- }
- switch (current->CounterType) {
- case PERF_COUNTER_COUNTER:
- case PERF_SAMPLE_COUNTER:
- case PERF_COUNTER_BULK_COUNT:
- // (N1 - N0) / ((D1 - D0) / F)
- numerator = current->Data - previous->Data;
- denominator = current->Time - previous->Time;
- dwordValue = (DWORD)(numerator / ((double)denominator / current->Frequency));
- //printf("Display value is (counter): %lu%s\n", (unsigned long)dwordValue,
- // (previous->CounterType == PERF_SAMPLE_COUNTER) ? "" : "/sec");
- return (double)dwordValue;
- case PERF_COUNTER_QUEUELEN_TYPE:
- case PERF_COUNTER_100NS_QUEUELEN_TYPE:
- case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
- case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
- case PERF_AVERAGE_BULK: // normally not displayed
- // (N1 - N0) / (D1 - D0)
- numerator = current->Data - previous->Data;
- denominator = current->Time - previous->Time;
- doubleValue = (double)numerator / denominator;
- if (previous->CounterType != PERF_AVERAGE_BULK) {
- // printf("Display value is (queuelen): %f\n", doubleValue);
- return doubleValue;
- }
- return NAN;
- case PERF_OBJ_TIME_TIMER:
- case PERF_COUNTER_TIMER:
- case PERF_100NSEC_TIMER:
- case PERF_PRECISION_SYSTEM_TIMER:
- case PERF_PRECISION_100NS_TIMER:
- case PERF_PRECISION_OBJECT_TIMER:
- case PERF_SAMPLE_FRACTION:
- // 100 * (N1 - N0) / (D1 - D0)
- numerator = current->Data - previous->Data;
- denominator = current->Time - previous->Time;
- doubleValue = (double)(100 * numerator) / denominator;
- // printf("Display value is (timer): %f%%\n", doubleValue);
- return doubleValue;
- case PERF_COUNTER_TIMER_INV:
- // 100 * (1 - ((N1 - N0) / (D1 - D0)))
- numerator = current->Data - previous->Data;
- denominator = current->Time - previous->Time;
- doubleValue = 100 * (1 - ((double)numerator / denominator));
- // printf("Display value is (timer-inv): %f%%\n", doubleValue);
- return doubleValue;
- case PERF_100NSEC_TIMER_INV:
- // 100 * (1- (N1 - N0) / (D1 - D0))
- numerator = current->Data - previous->Data;
- denominator = current->Time - previous->Time;
- doubleValue = 100 * (1 - (double)numerator / denominator);
- // printf("Display value is (100ns-timer-inv): %f%%\n", doubleValue);
- return doubleValue;
- case PERF_COUNTER_MULTI_TIMER:
- // 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
- numerator = current->Data - previous->Data;
- denominator = current->Time - previous->Time;
- denominator /= current->Frequency;
- doubleValue = 100 * ((double)numerator / denominator) / current->MultiCounterData;
- // printf("Display value is (multi-timer): %f%%\n", doubleValue);
- return doubleValue;
- case PERF_100NSEC_MULTI_TIMER:
- // 100 * ((N1 - N0) / (D1 - D0)) / B1
- numerator = current->Data - previous->Data;
- denominator = current->Time - previous->Time;
- doubleValue = 100 * ((double)numerator / (double)denominator) / (double)current->MultiCounterData;
- // printf("Display value is (100ns multi-timer): %f%%\n", doubleValue);
- return doubleValue;
- case PERF_COUNTER_MULTI_TIMER_INV:
- case PERF_100NSEC_MULTI_TIMER_INV:
- // 100 * (B1 - ((N1 - N0) / (D1 - D0)))
- numerator = current->Data - previous->Data;
- denominator = current->Time - previous->Time;
- doubleValue = 100.0 * ((double)current->MultiCounterData - ((double)numerator / (double)denominator));
- // printf("Display value is (multi-timer-inv): %f%%\n", doubleValue);
- return doubleValue;
- case PERF_COUNTER_RAWCOUNT:
- case PERF_COUNTER_LARGE_RAWCOUNT:
- // N as decimal
- // printf("Display value is (rawcount): %llu\n", current->Data);
- return (double)current->Data;
- case PERF_COUNTER_RAWCOUNT_HEX:
- case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
- // N as hexadecimal
- // printf("Display value is (hex): 0x%llx\n", current->Data);
- return (double)current->Data;
- case PERF_COUNTER_DELTA:
- case PERF_COUNTER_LARGE_DELTA:
- // N1 - N0
- // printf("Display value is (delta): %llu\n", current->Data - previous->Data);
- return (double)(current->Data - previous->Data);
- case PERF_RAW_FRACTION:
- case PERF_LARGE_RAW_FRACTION:
- // 100 * N / B
- doubleValue = 100.0 * (double)current->Data / (double)current->Time;
- // printf("Display value is (fraction): %f%%\n", doubleValue);
- return doubleValue;
- case PERF_AVERAGE_TIMER:
- // ((N1 - N0) / TB) / (B1 - B0)
- numerator = current->Data - previous->Data;
- denominator = current->Time - previous->Time;
- doubleValue = (double)numerator / (double)current->Frequency / (double)denominator;
- // printf("Display value is (average timer): %f seconds\n", doubleValue);
- return doubleValue;
- case PERF_ELAPSED_TIME:
- // (D0 - N0) / F
- doubleValue = (double)(current->Time - current->Data) / (double)current->Frequency;
- // printf("Display value is (elapsed time): %f seconds\n", doubleValue);
- return doubleValue;
- case PERF_COUNTER_TEXT:
- case PERF_SAMPLE_BASE:
- case PERF_AVERAGE_BASE:
- case PERF_COUNTER_MULTI_BASE:
- case PERF_RAW_BASE:
- case PERF_COUNTER_NODATA:
- case PERF_PRECISION_TIMESTAMP:
- // printf(" > Non-printing counter type: 0x%08x\n", current->CounterType);
- return NAN;
- break;
- default:
- // printf(" > Unrecognized counter type: 0x%08x\n", current->CounterType);
- return NAN;
- break;
- }
- }
- */
|