Skip to content

Commit 0140658

Browse files
Fix thread utilization on Windows (#1469)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent 9bad19a commit 0140658

File tree

2 files changed

+45
-25
lines changed

2 files changed

+45
-25
lines changed

newrelic/core/_thread_utilization.c

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,22 @@
1616

1717
/* ------------------------------------------------------------------------- */
1818

19-
#include <sys/time.h>
2019
#include <Python.h>
2120
#include <pythread.h>
2221

22+
#ifdef _WIN32
23+
24+
#include <windows.h>
25+
#include <minwinbase.h>
26+
#include <sysinfoapi.h>
27+
#include <winnt.h>
28+
29+
#else
30+
31+
#include <sys/time.h>
32+
33+
#endif
34+
2335
#ifndef PyVarObject_HEAD_INIT
2436
#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
2537
#endif
@@ -34,20 +46,39 @@ typedef struct {
3446
long long time_last_fetched;
3547
} UtilizationCount;
3648

37-
static void reset_utilization_count(UtilizationCount *self)
49+
static void get_current_time_usecs(long long *ts)
3850
{
39-
struct timeval t;
51+
#ifdef _WIN32
52+
FILETIME ft;
53+
ULARGE_INTEGER t;
54+
55+
// Most accurate timestamp available on Windows.
56+
// Measured in 100ns intervals since January 1, 1601 (UTC).
57+
GetSystemTimePreciseAsFileTime(&ft);
58+
59+
// Convert FILETIME to a 64-bit integer
60+
t.LowPart = ft.dwLowDateTime;
61+
t.HighPart = ft.dwHighDateTime;
62+
63+
// Convert from 100ns intervals to microseconds
64+
*ts = (long long) (t.QuadPart / 10);
65+
#else
66+
struct timeval t;
67+
68+
gettimeofday(&t, NULL);
69+
*ts = (t.tv_sec * 1000000) + t.tv_usec;
70+
#endif
71+
}
72+
4073

74+
static void reset_utilization_count(UtilizationCount *self)
75+
{
4176
self->currently_active = 0;
4277

4378
self->utilization_current = 0.0;
4479
self->utilization_previous = 0.0;
4580

46-
gettimeofday(&t, NULL);
47-
48-
self->time_last_updated = t.tv_sec * 1000000;
49-
self->time_last_updated += t.tv_usec;
50-
81+
get_current_time_usecs(&self->time_last_updated);
5182
self->time_last_fetched = self->time_last_updated;
5283
}
5384

@@ -56,12 +87,7 @@ static double adjust_utilization_count(UtilizationCount *self, int adjustment)
5687
long long current_time;
5788
double utilization = self->utilization_current;
5889

59-
struct timeval t;
60-
61-
gettimeofday(&t, NULL);
62-
63-
current_time = t.tv_sec * 1000000;
64-
current_time += t.tv_usec;
90+
get_current_time_usecs(&current_time);
6591

6692
utilization = (current_time - self->time_last_updated) / 1000000.0;
6793

@@ -104,8 +130,8 @@ static double fetch_utilization_count(UtilizationCount *self)
104130

105131
time_last_updated = self->time_last_updated;
106132

107-
elapsed_time = self->time_last_updated - time_last_fetched;
108-
elapsed_time /= 1000000.0;
133+
// Convert to interval in seconds
134+
elapsed_time = (self->time_last_updated - time_last_fetched) / 1000000.0;
109135

110136
if (elapsed_time <= 0)
111137
return 0.0;
@@ -210,11 +236,7 @@ static double NRUtilization_adjust(NRUtilizationObject *self, int adjustment)
210236
long long now;
211237
double utilization = self->requests_utilization_count;
212238

213-
struct timeval t;
214-
215-
gettimeofday(&t, NULL);
216-
217-
now = ((long long)t.tv_sec) * 1000000 + ((long long)t.tv_usec);
239+
get_current_time_usecs(&now);
218240

219241
if (self->requests_utilization_last != 0.0) {
220242
utilization = (now - self->requests_utilization_last) / 1000000.0;

setup.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,10 @@ def _run_setup():
209209
if with_extensions:
210210
kwargs_tmp["ext_modules"] = [
211211
Extension("newrelic.packages.wrapt._wrappers", ["newrelic/packages/wrapt/_wrappers.c"]),
212+
Extension("newrelic.core._thread_utilization", ["newrelic/core/_thread_utilization.c"]),
212213
]
213214
if not is_windows:
214-
# These extensions are only supported on POSIX platforms.
215+
# This extension is only supported on POSIX platforms.
215216
monotonic_libraries = []
216217
if with_librt():
217218
monotonic_libraries = ["rt"]
@@ -221,9 +222,6 @@ def _run_setup():
221222
"newrelic.common._monotonic", ["newrelic/common/_monotonic.c"], libraries=monotonic_libraries
222223
)
223224
)
224-
kwargs_tmp["ext_modules"].append(
225-
Extension("newrelic.core._thread_utilization", ["newrelic/core/_thread_utilization.c"])
226-
)
227225

228226
kwargs_tmp["cmdclass"] = dict(build_ext=optional_build_ext)
229227

0 commit comments

Comments
 (0)