summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/src/support/global.c
blob: c2c41810d66472cb74eef668796ff48550007cdb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*-
 * Copyright (c) 2014-2019 MongoDB, Inc.
 * Copyright (c) 2008-2014 WiredTiger, Inc.
 *	All rights reserved.
 *
 * See the file LICENSE for redistribution information.
 */

#include "wt_internal.h"

WT_PROCESS __wt_process;			/* Per-process structure */
static int __wt_pthread_once_failed;		/* If initialization failed */

/*
 * __endian_check --
 *	Check the build matches the machine.
 */
static int
__endian_check(void)
{
	uint64_t v;
	const char *e;
	bool big;

	v = 1;
	big = *((uint8_t *)&v) == 0;

#ifdef WORDS_BIGENDIAN
	if (big)
		return (0);
	e = "big-endian";
#else
	if (!big)
		return (0);
	e = "little-endian";
#endif
	fprintf(stderr,
	    "This is a %s build of the WiredTiger data engine, incompatible "
	    "with this system\n", e);
	return (EINVAL);
}

/*
 * __global_calibrate_ticks --
 *	Calibrate a ratio from rdtsc ticks to nanoseconds.
 */
static void
__global_calibrate_ticks(void)
{
	/*
	 * Default to using __wt_epoch until we have a good value for the ratio.
	 */
	__wt_process.tsc_nsec_ratio = WT_TSC_DEFAULT_RATIO;
	__wt_process.use_epochtime = true;

#if defined (__i386) || defined (__amd64)
	{
	struct timespec start, stop;
	double ratio;
	uint64_t diff_nsec, diff_tsc, min_nsec, min_tsc;
	uint64_t tries, tsc_start, tsc_stop;
	volatile uint64_t i;

	/*
	 * Run this calibration loop a few times to make sure we get a
	 * reading that does not have a potential scheduling shift in it.
	 * The inner loop is CPU intensive but a scheduling change in the
	 * middle could throw off calculations. Take the minimum amount
	 * of time and compute the ratio.
	 */
	min_nsec = min_tsc = UINT64_MAX;
	for (tries = 0; tries < 3; ++tries) {
		/* This needs to be CPU intensive and large enough. */
		__wt_epoch(NULL, &start);
		tsc_start = __wt_rdtsc();
		for (i = 0; i < 100 * WT_MILLION; i++)
			;
		tsc_stop = __wt_rdtsc();
		__wt_epoch(NULL, &stop);
		diff_nsec = WT_TIMEDIFF_NS(stop, start);
		diff_tsc = tsc_stop - tsc_start;

		/* If the clock didn't tick over, we don't have a sample. */
		if (diff_nsec == 0 || diff_tsc == 0)
			continue;
		min_nsec = WT_MIN(min_nsec, diff_nsec);
		min_tsc = WT_MIN(min_tsc, diff_tsc);
	}

	/*
	 * Only use rdtsc if we got a good reading.  One reason this might fail
	 * is that the system's clock granularity is not fine-grained enough.
	 */
	if (min_nsec != UINT64_MAX) {
		ratio = (double)min_tsc / (double)min_nsec;
		if (ratio > DBL_EPSILON) {
			__wt_process.tsc_nsec_ratio = ratio;
			__wt_process.use_epochtime = false;
		}
	}
	}
#endif
}

/*
 * __global_once --
 *	Global initialization, run once.
 */
static void
__global_once(void)
{
	WT_DECL_RET;

	if ((ret =
	    __wt_spin_init(NULL, &__wt_process.spinlock, "global")) != 0) {
		__wt_pthread_once_failed = ret;
		return;
	}

	TAILQ_INIT(&__wt_process.connqh);

#if defined(HAVE_PAGE_VERSION_TS)
	__wt_process.page_version_ts = true;
#else
	__wt_process.page_version_ts = false;
#endif

	__wt_process.checksum = wiredtiger_crc32c_func();

	__global_calibrate_ticks();
}

/*
 * __wt_library_init --
 *	Some things to do, before we do anything else.
 */
int
__wt_library_init(void)
{
	static bool first = true;
	WT_DECL_RET;

	/* Check the build matches the machine. */
	WT_RET(__endian_check());

	/*
	 * Do per-process initialization once, before anything else, but only
	 * once.  I don't know how heavy-weight the function (pthread_once, in
	 * the POSIX world), might be, so I'm front-ending it with a local
	 * static and only using that function to avoid a race.
	 */
	if (first) {
		if ((ret = __wt_once(__global_once)) != 0)
			__wt_pthread_once_failed = ret;
		first = false;
	}
	return (__wt_pthread_once_failed);
}