Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

export DragonFlyBSD CPU time #310

Merged
merged 17 commits into from
Nov 17, 2016
Merged

Conversation

stuartnelson3
Copy link
Contributor

@stuartnelson3 stuartnelson3 commented Sep 18, 2016

Hey,

This reports the node cpu time for machines running DragonFlyBSD. It is analogous to cpu_freebsd.go, but unfortunately DragonFly required a different implementation.

The code here is heavily influenced by the FreeBSD implementation, as well as this:

https://www.dragonflybsd.org/mailarchive/users/2010-04/msg00056.html

I have a separate implementation that uses creates a go slice from a C array of the double values, instead of how this implementation uses a string, if that is preferred: https://github.com/stuartnelson3/node_exporter/blob/dfly-cpu-doubles/collector/cpu_dragonfly.go

Note:

The units seem to be off by perhaps 3 orders of magnitude. I'm waiting for a response from the DragonFly community as to what the units for the various cpu modes.

FIXED: It seems I was using the incorrect value to find cpu time. The value I should use is the systimer_freq. The pr has been updated to use that.

Might not be lined up correctly? Weird output data
in the second CPU.
Don't need it since we aren't malloc'ing
Moved to exporting via a string, which is then
split and parsed.

The string is sometimes duplicated, however.
Duplication was caused by malloc returning a
region of memory that already had data in it.
@stuartnelson3 stuartnelson3 changed the title Dfly cpu export DragonFlyBSD CPU time Sep 18, 2016
The correct frequency is the systimer frequency,
not the stathz.

From one of the DragonFly developers:

The bump upon each statclock is:
((cur_systimer - prev_systimer) * systimer_freq) >> 32

systimer_freq can be extracted from following
sysctl in userspace:
sysctl kern.cputimer.freq
This is the code that was lifted from the freebsd
implementation, but was not correct.
Copy link
Contributor

@matthiasr matthiasr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I think I prefer pulling values out instead of the string conversion (and associated buffer size issues).

I think in general it would be beneficial to do less in C and more in Go; this should make it easier to verify the C parts.

What about tests?


// string needs to hold (5*ncpu)(uint64_t + char)
// The char is the space between values.
int cputime_size = (sizeof(uint64_t)+sizeof(char))*(5*ncpu);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sizeof(uint64_t) is not the size of the decimal expansion you're actually putting into the string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any help is welcome, I'm not a C programmer :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sizeof is the size of the binary representation (8), but (if the number is large) the decimal representation you're putting in this array will be longer. 2^64-1 has 20 digits, so I think if you just put in 5_ncpu_21 it'll be enough?

Additionally, instead of malloc+bzero you can use calloc below – memory returned from calloc is initialized to 0: *cputime = calloc(ncpu, 5*21) should do.

I'm not a C programmer either …

uint64_t user, nice, sys, intr, idle;
user = nice = sys = intr = idle = 0;
for (int i = 0; i < ncpu; ++i) {
user = ((double) cp_t[i].cp_user) / freq;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is integer seconds? This conversion/division is very lossy; can we get more granularity out? Either by putting micro- or nanoseconds in the string, or by using floats?

Or read the frequency separately, get cp_t out in to Go land as is, and do the math in Go?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to read out the values separately and do the math in Go land. I would prefer to stick with exporting in a string, as my initial attempts at pulling out the struct and moving it to go didn't end well.

Export cpu mode times as original uint64_t data,
and update frequency, and do the conversion to
float64 and subsequent division in go.
@stuartnelson3
Copy link
Contributor Author

@matthiasr I think this latest commit might address both your concerns. The value being written to the string is now uint64_t instead of double, so I think my size calculation will be correct (maybe, still not sure, and google searches only turn up C++ stdlib conversion code), and the division to find cpu time in seconds is being executed with higher fidelity types.

Example scrape output:

# HELP node_cpu Seconds the cpus spent in each mode.
# TYPE node_cpu counter
node_cpu{cpu="cpu0",mode="idle"} 123.2041996957714
node_cpu{cpu="cpu0",mode="interrupt"} 0.05891468049710229
node_cpu{cpu="cpu0",mode="nice"} 0.01800515149271765
node_cpu{cpu="cpu0",mode="sys"} 3.9195816786770385
node_cpu{cpu="cpu0",mode="user"} 6.904898737129998
node_cpu{cpu="cpu1",mode="idle"} 122.07772426383801
node_cpu{cpu="cpu1",mode="interrupt"} 0.034394175796085814
node_cpu{cpu="cpu1",mode="nice"} 0.0070924516942795805
node_cpu{cpu="cpu1",mode="sys"} 4.034886137763319
node_cpu{cpu="cpu1",mode="user"} 7.951272577939375

Where previous values were just integers.

@stuartnelson3
Copy link
Contributor Author

This seems to produce the correct results when putting my machine under load:

screenshot at 2016-09-20 09 52 24

@stuartnelson3
Copy link
Contributor Author

@matthiasr moved to doing all the math in go-land (exporting values as uint64_t and doing conversion to float64 in go), and I added a test.

I'm really not sure what you're looking for regarding the test. Let me know.

Copy link
Contributor

@matthiasr matthiasr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@stuartnelson3
Copy link
Contributor Author

any chance you wanna merge this? :)

@stuartnelson3
Copy link
Contributor Author

@fabxc any love?

@stuartnelson3 stuartnelson3 deleted the dfly-cpu branch October 30, 2018 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants