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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#include "internal.hpp"
/*------------------------------------------------------------------------*/
// Our random number generator is seeded by default (i.e., in the default
// constructor) with random seeds, which should be unique across machines,
// processes and time. This makes this code below rather operating system
// dependent. We also use in essence defensive programming, overlaying
// several methods to get randomness since in the past we were bitten a
// couple of times (and got the same seeds). Having several methods makes
// it also simpler to port randomly initializing seeds to different
// operating systems (even though currently it is only tested on Linux).
// This functionality is only used in the 'Mobical' model based tester at
// this point, since the main solver explicitly sets a random seed ('0' by
// default in 'options.hpp') and also currently only uses this seed in the
// local search procedure explicitly without using the default constructor.
// It is crucial for 'Mobical' to make sure that concurrent runs are really
// independent.
/*------------------------------------------------------------------------*/
// Uncomment the following definition to force printing the computed hash
// values for individual machine and process properties. This is only needed
// for testing, porting and debugging different ports of this seeding and
// hashing functions (uncomment and run 'mobical' for instance).
/*
#define DO_PRINT_HASH
*/
#ifdef DO_PRINT_HASH
#define PRINT_HASH(H) \
do { \
printf ("c PRINT_HASH %32s () = %020" PRIu64 "\n", __func__, H); \
fflush (stdout); \
} while (0)
#else
#define PRINT_HASH(...) \
do { \
} while (0)
#endif
/*------------------------------------------------------------------------*/
// This is Linux specific but if '/var/lib/dbus/machine-id' does not exist
// does not have any effect. TODO: add a similar machine identity hashing
// function for other operating systems (Windows and macOS).
namespace CaDiCaL {
static uint64_t hash_machine_identifier () {
FILE *file = fopen ("/var/lib/dbus/machine-id", "r");
uint64_t res = 0;
if (file) {
char buffer[128];
memset (buffer, 0, sizeof buffer);
size_t bytes = fread (buffer, 1, sizeof buffer - 1, file);
assert (bytes);
fclose (file);
if (bytes && bytes < sizeof buffer) {
buffer[bytes] = 0;
res = hash_string (buffer);
}
}
PRINT_HASH (res);
return res;
}
} // namespace CaDiCaL
/*------------------------------------------------------------------------*/
// On our Linux cluster where we used an NFS mounted root disk the
// 'machine-id' above (even on a locally mounted '/var' disk on each node)
// was copied from '/etc/machine-id' which was shared among all nodes
// (before figuring this out and fixing it). Thus the main idea of getting
// different hash values through this machine identifier machines did not
// work. As an additional measure to increase the possibility to get
// different seeds we are now also using network addresses (explicitly).
#ifndef _WIN32
extern "C" {
#include <ifaddrs.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
}
#endif
namespace CaDiCaL {
static uint64_t hash_network_addresses () {
uint64_t res = 0;
// We still need to properly port this to Windows, but since accessing the
// IP address is only required for better randomization during testing
// (running 'mobical' on a cluster for instance) it is not crucial unless
// you really need to run 'mobical' on a Windows cluster where each node
// has identical IP addresses.
#ifndef _WIN32
struct ifaddrs *addrs;
if (!getifaddrs (&addrs)) {
for (struct ifaddrs *addr = addrs; addr; addr = addr->ifa_next) {
if (!addr->ifa_addr)
continue;
const int family = addr->ifa_addr->sa_family;
if (family == AF_INET || family == AF_INET6) {
const int size = (family == AF_INET) ? sizeof (struct sockaddr_in)
: sizeof (struct sockaddr_in6);
char buffer[128];
if (!getnameinfo (addr->ifa_addr, size, buffer, sizeof buffer, 0, 0,
NI_NUMERICHOST)) {
uint64_t tmp = hash_string (buffer);
#ifdef DO_PRINT_HASH
printf ("c PRINT_HASH %35s = %020" PRIu64 "\n", buffer, tmp);
fflush (stdout);
#endif
res ^= tmp;
res *= 10000000000000000051ul;
}
}
}
freeifaddrs (addrs);
}
#endif
PRINT_HASH (res);
return res;
}
} // namespace CaDiCaL
/*------------------------------------------------------------------------*/
// Hash the current wall-clock time in seconds.
extern "C" {
#include <time.h>
}
namespace CaDiCaL {
static uint64_t hash_time () {
uint64_t res = ::time (0);
PRINT_HASH (res);
return res;
}
} // namespace CaDiCaL
/*------------------------------------------------------------------------*/
// Hash the process identified.
extern "C" {
#include <sys/types.h>
#include <unistd.h>
}
namespace CaDiCaL {
static uint64_t hash_process () {
uint64_t res = getpid ();
PRINT_HASH (res);
return res;
}
} // namespace CaDiCaL
/*------------------------------------------------------------------------*/
// Hash the current number of clock cycles.
#include <ctime>
namespace CaDiCaL {
static uint64_t hash_clock_cycles () {
uint64_t res = std::clock ();
PRINT_HASH (res);
return res;
}
} // namespace CaDiCaL
/*------------------------------------------------------------------------*/
namespace CaDiCaL {
Random::Random () : state (1) {
add (hash_machine_identifier ());
add (hash_network_addresses ());
add (hash_clock_cycles ());
add (hash_process ());
add (hash_time ());
#ifdef DO_PRINT_HASH
printf ("c PRINT_HASH %32s = %020" PRIu64 "\n", "combined", state);
fflush (stdout);
#endif
}
} // namespace CaDiCaL