This source file includes following definitions.
- sim_hrline
- is_jailed
- is_static_linked_selfelf
- is_static_linked_selfmap
- is_static_linked
- is_ntp_sync
- has_linux_capability
- check_cpu_frequencies
- is_raspberry_pi
- check_pi_issues
- check_scaling_governors
- atm_cwords
- processIsTranslated
- show_hints
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include "sim_defs.h"
21
22 #include <ctype.h>
23 #include <dirent.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <limits.h>
27 #include <stdatomic.h>
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #if !defined(_WIN32)
35 # include <sys/resource.h>
36 #endif
37 #include <time.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41 #if defined(__APPLE__)
42 # include <sys/sysctl.h>
43 #endif
44 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || \
45 defined(__illumos__) || defined(__linux__) && !defined(__ANDROID__)
46 # include <sys/timex.h>
47 #endif
48 #if defined(__FreeBSD__) || defined(__DragonFly__)
49 # include <sys/sysctl.h>
50 #endif
51
52 #include "linehistory.h"
53
54 #include "../dps8/dps8.h"
55 #include "../dps8/dps8_cpu.h"
56 #include "../dps8/dps8_topo.h"
57
58 #include "../simh/sim_os_mem.h"
59 #include "../simh/scp.h"
60
61
62
63
64
65
66 #include "../dps8/dps8_sir.h"
67
68 #if !defined(HAS_INCLUDE)
69 # if defined __has_include
70 # define HAS_INCLUDE(inc) __has_include(inc)
71 # else
72 # define HAS_INCLUDE(inc) 0
73 # endif
74 #endif
75
76 #if defined(__linux__)
77 # if HAS_INCLUDE(<linux/capability.h>)
78 # include <linux/capability.h>
79 # endif
80 # if !defined(CAP_SYS_NICE)
81 # define CAP_SYS_NICE 23
82 # endif
83 # if !defined(CAP_IPC_LOCK)
84 # define CAP_IPC_LOCK 14
85 # endif
86 #endif
87
88 #if !defined(__APPLE__)
89 # if HAS_INCLUDE(<elf.h>)
90 # include <elf.h>
91 # endif
92 #endif
93
94 #undef USE_ELF_H
95 #if defined(EI_MAG0) && defined(EI_MAG1) && defined(EI_MAG2) && defined(EI_MAG3) && \
96 defined(ELFMAG0) && defined(ELFMAG1) && defined(ELFMAG2) && defined(ELFMAG3) && \
97 defined(PT_DYNAMIC) && !defined(_WIN32)
98 # if defined(USHRT_MAX)
99 # define MAX_HEADERS USHRT_MAX
100 # else
101 # define MAX_HEADERS 65535
102 # endif
103 # define USE_ELF_H
104 #endif
105
106 #if !defined(_WIN32)
107 # include <sys/mman.h>
108 #endif
109
110 #undef PROC_SELF
111 #if defined(__linux__) || defined(__serenity__)
112 # define PROC_SELF "/proc/self/exe"
113 #elif defined(__NetBSD__)
114 # define PROC_SELF "/proc/curproc/exe"
115 #elif defined(__FreeBSD__) || defined(__DragonFly__)
116 # define PROC_SELF "/proc/curproc/file"
117 #elif defined(__sun) || defined(__illumos__)
118 # define PROC_SELF "/proc/self/path/a.out"
119 #endif
120
121 #if defined(__managarm__)
122 # if !defined(FORCE_STATIC)
123 # define FORCE_STATIC
124 # endif
125 #endif
126
127 #if !defined(CHAR_BIT)
128 # define CHAR_BIT 8
129 #endif
130
131 unsigned int hint_count = 0;
132
133
134
135 static inline void
136 sim_hrline(void)
137 {
138 sim_printf("\r\n------------------------------------------------------------------------------\r\n");
139 }
140
141
142
143 static int
144 is_jailed(void)
145 {
146 int jailed = 0;
147 size_t len = sizeof(jailed);
148
149 #if defined(__FreeBSD__) || defined(__DragonFly__)
150 if (-1 == sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0))
151 return false;
152 #endif
153
154 (void)len;
155
156 if (jailed)
157 return true;
158
159 return false;
160 }
161
162
163
164 #if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32) && !defined(FORCE_STATIC) && \
165 !defined(__FILC__)
166 static int
167 is_static_linked_selfelf(void)
168 {
169 # if !defined(USE_ELF_H)
170 return -1;
171 # elif defined(__APPLE__)
172 return -1;
173 # else
174 char *self_exe;
175
176 # ifdef PROC_SELF
177 self_exe = PROC_SELF;
178 # else
179 self_exe = sim_appfilename;
180 # endif
181
182 int fd = open(self_exe, O_RDONLY);
183
184 if (fd < 0) {
185 self_exe = sim_appfilename;
186 fd = open(self_exe, O_RDONLY);
187 if (fd < 0)
188 return -1;
189 }
190
191 struct stat st;
192 if (fstat(fd, &st) < 0) {
193 (void)close(fd);
194 return -1;
195 }
196
197 void *map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
198 if (MAP_FAILED == map) {
199 (void)close(fd);
200 return -1;
201 }
202
203 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)map;
204
205 if (ELFMAG0 != ehdr->e_ident[EI_MAG0] ||
206 ELFMAG1 != ehdr->e_ident[EI_MAG1] ||
207 ELFMAG2 != ehdr->e_ident[EI_MAG2] ||
208 ELFMAG3 != ehdr->e_ident[EI_MAG3]) {
209 (void)munmap(map, st.st_size);
210 (void)close(fd);
211 return -1;
212 }
213
214 Elf64_Phdr *phdr;
215 void *phdr_address = (void *)((char *)map + ehdr->e_phoff);
216 (void)memcpy(&phdr, &phdr_address, sizeof(phdr));
217
218 if (0 == ehdr->e_phnum || ehdr->e_phnum > MAX_HEADERS) {
219 (void)munmap(map, st.st_size);
220 (void)close(fd);
221 return -1;
222 }
223
224 for (unsigned int i = 0; i < ehdr->e_phnum; i++)
225 if (PT_DYNAMIC == phdr[i].p_type) {
226 (void)munmap(map, st.st_size);
227 (void)close(fd);
228 return 0;
229 }
230
231 (void)munmap(map, st.st_size);
232 (void)close(fd);
233 return 1;
234 # endif
235 }
236 #endif
237
238
239
240 #if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32) && !defined(FORCE_STATIC) && \
241 !defined(__FILC__)
242 static int
243 is_static_linked_selfmap (void)
244 {
245 FILE *maps = fopen ("/proc/self/maps", "r");
246
247 if (!maps)
248 return -1;
249
250 char line[256];
251 while (fgets (line, sizeof (line), maps))
252 if (strstr(line, "/ld-") ||
253 strstr(line, "/system/bin/linker") ||
254 strstr(line, "/lib/ld")) {
255 (void)fclose (maps);
256 return 0;
257 }
258
259 (void)fclose (maps);
260 return 1;
261 }
262 #endif
263
264
265
266 #if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32) && !defined(FORCE_STATIC) && \
267 !defined(__FILC__)
268 static int
269 is_static_linked (void)
270 {
271 int map = is_static_linked_selfmap ();
272 int elf = is_static_linked_selfelf ();
273
274 # if defined(STATIC_TESTING)
275 (void)fprintf(stderr, "is_static_linked_selfmap=%d\r\n", map);
276 (void)fprintf(stderr, "is_static_linked_selfelf=%d\r\n", elf);
277 # endif
278
279 if (-1 == map && -1 == elf)
280 return -1;
281
282 if (-1 == map)
283 return elf;
284
285 if (-1 == elf)
286 return map;
287
288 if (map != elf)
289 return -1;
290
291 return map;
292 }
293 #endif
294
295
296
297 static int
298 is_ntp_sync (void)
299 {
300 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || \
301 defined(__illumos__) || defined(__linux__) && !defined(__ANDROID__) && \
302 !defined(__FILC__)
303 struct timex tx = { 0 };
304 # if defined(__FreeBSD__) || defined(__NetBSD__) || \
305 defined(__sun) || defined(__illumos__)
306 int result = ntp_adjtime (&tx);
307 # else
308 int result = adjtimex (&tx);
309 # endif
310 if (-1 == result)
311 return -1;
312 # if defined(__sun) || defined(__illumos__)
313 if (tx.status & STA_UNSYNC)
314 # else
315 if (TIME_OK != result)
316 # endif
317 if (1000000 >= tx.maxerror)
318 return 1;
319 else
320 return 0;
321 else
322 return 2;
323 #else
324 return -1;
325 #endif
326 }
327
328
329
330 #if defined(__linux__) && !defined(__ANDROID__)
331 static int
332 has_linux_capability(const pid_t pid, const int capability)
333 {
334 char filename[SIR_MAXPATH];
335 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
336
337 FILE *file = fopen(filename, "r");
338 if (!file)
339 return -1;
340
341 char line[1024];
342 uint64_t cap_eff = 0;
343
344 while (fgets(line, sizeof(line), file))
345 if (1 == sscanf(line, "CapEff: %llx", (long long unsigned int*)&cap_eff))
346 break;
347
348 fclose(file);
349
350 return 0 != (cap_eff & (1ULL << capability));
351 }
352 #endif
353
354
355
356 static int
357 check_cpu_frequencies (void)
358 {
359 #if !defined(__linux__)
360 return 0;
361 #else
362 struct dirent *entry;
363 char path[SIR_MAXPATH];
364 FILE *file;
365 int min_freq = 0, max_freq = 0;
366 int mismatch = 0;
367
368 DIR *dir = opendir ("/sys/devices/system/cpu");
369
370 if (!dir)
371 return 0;
372
373 while ((entry = readdir (dir)) != NULL) {
374 if (DT_DIR == entry->d_type && 0 == strncmp (entry->d_name, "cpu", 3)
375 && isdigit (entry->d_name[3])) {
376 snprintf (path, sizeof (path), "/sys/devices/system/cpu/%s/cpufreq/cpuinfo_min_freq",
377 entry->d_name);
378 file = fopen (path, "r");
379 if (file) {
380 if (1 != fscanf (file, "%d", &min_freq)) {
381 fclose (file);
382 min_freq = -1;
383 } else {
384 fclose (file);
385 }
386 }
387 snprintf (path, sizeof (path), "/sys/devices/system/cpu/%s/cpufreq/cpuinfo_max_freq",
388 entry->d_name);
389 file = fopen (path, "r");
390 if (file) {
391 if (1 != fscanf (file, "%d", &max_freq)) {
392 fclose (file);
393 max_freq = -1;
394 } else {
395 fclose (file);
396 }
397 }
398 if (-1 != min_freq && -1 != max_freq && min_freq != max_freq) {
399 mismatch = 1;
400 }
401 }
402 }
403 closedir (dir);
404
405 if (mismatch) {
406 return 1;
407 } else {
408 return 0;
409 }
410 #endif
411 }
412
413
414
415 #define RPI_TEXT "Raspberry Pi"
416
417 static int
418 is_raspberry_pi (void)
419 {
420 FILE *file;
421 char line[1024];
422 int is_pi = 0;
423
424 file = fopen("/proc/device-tree/model", "r");
425 if (file) {
426 if (fgets(line, sizeof(line), file) && strstr(line, RPI_TEXT))
427 is_pi = 1;
428 fclose(file);
429 if (is_pi)
430 return 1;
431 }
432
433 file = fopen("/proc/cpuinfo", "r");
434 if (!file)
435 return 0;
436
437 while (fgets(line, sizeof(line), file)) {
438 if (strncmp(line, "Model", 5) == 0 && strstr(line, RPI_TEXT)) {
439 is_pi = 1;
440 break;
441 }
442 }
443 fclose(file);
444
445 return is_pi;
446 }
447
448
449
450 static uint32_t
451 check_pi_issues (void)
452 {
453 uint32_t a_issues = 0;
454
455 FILE *fp = popen("vcgencmd get_throttled 2> /dev/null", "r");
456 if (!fp)
457 return a_issues;
458
459 char buffer[1024];
460 if (NULL == fgets(buffer, sizeof(buffer), fp)) {
461 pclose(fp);
462 return a_issues;
463 }
464 pclose(fp);
465
466 char *p = strstr(buffer, "0x");
467 if (!p)
468 return a_issues;
469
470 uint32_t throttle = (uint32_t)strtoul(p, NULL, 16);
471 uint32_t c_issues = throttle & 0xF;
472 uint32_t p_issues = (throttle >> 16) & 0xF;
473 a_issues = c_issues | p_issues;
474
475 return a_issues;
476 }
477
478
479
480 static uint32_t
481 check_scaling_governors (void)
482 {
483 #if !defined(__linux__)
484 return 0;
485 #else
486 struct dirent *entry;
487 char path[SIR_MAXPATH];
488 FILE *file;
489 char governor[256];
490 static uint32_t bad_govs;
491
492 DIR *dir = opendir ("/sys/devices/system/cpu");
493
494 if (!dir)
495 return 0;
496
497 bad_govs = 0;
498 while ((entry = readdir (dir)) != NULL) {
499 if (DT_DIR == entry->d_type && 0 == strncmp (entry->d_name, "cpu", 3)
500 && isdigit (entry->d_name[3])) {
501 snprintf (path, sizeof (path), "/sys/devices/system/cpu/%s/cpufreq/scaling_governor",
502 entry->d_name);
503 file = fopen (path, "r");
504 if (file) {
505 if (fgets (governor, sizeof (governor), file)) {
506 governor[strcspn (governor, "\n")] = '\0';
507 if ( 0 == strcmp (governor, "powersave" )
508 || 0 == strcmp (governor, "conservative") ) {
509 bad_govs++;
510 }
511 }
512 fclose (file);
513 }
514 }
515 }
516 closedir (dir);
517
518 return bad_govs;
519 #endif
520 }
521
522
523
524 const char *
525 atm_cwords (int count)
526 {
527 static const char *words[] = { "Zero", "One", "Two", "Three", "Four", "Five", "Six" };
528 static char buffer[20];
529
530 if (count >= 0 && count <= 6) {
531 return words[count];
532 } else {
533 snprintf (buffer, sizeof (buffer), "%d", count);
534 return buffer;
535 }
536 }
537
538
539
540 #if defined(__APPLE__)
541 static int
542 processIsTranslated (void)
543 {
544 int ret = 0;
545 size_t size = sizeof(ret);
546 if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
547 if (errno == ENOENT)
548 return 0;
549 return -1;
550 }
551 return ret;
552 }
553 #endif
554
555
556
557 t_stat
558 show_hints (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
559 {
560
561
562 hint_count = 0;
563
564
565
566
567 if (64 > (sizeof (time_t) * CHAR_BIT)) {
568 if (!flag) {
569 sim_hrline ();
570 sim_printf ("\r\n* Hint #%u - LESS THAN 64-BIT TIME REPRESENTATION DETECTED\r\n", ++hint_count);
571 sim_printf ("\r\n");
572 sim_printf (" The simulator has detected timekeeping using a %ld-bit representation.\r\n",
573 (long)(sizeof (time_t) * CHAR_BIT));
574 } else {
575 ++hint_count;
576 }
577 }
578
579
580
581
582 #if !defined(__HAIKU__) && !defined(_WIN32)
583 if (0 == geteuid ()) {
584 if (!flag) {
585 sim_hrline ();
586 sim_printf ("\r\n* Hint #%u - SIMULATOR RUNNING AS ROOT OR SUPERUSER DETECTED\r\n", ++hint_count);
587 sim_printf ("\r\n");
588 sim_printf (" You are running the simulator as `root` (or equivalent superuser).\r\n");
589 sim_printf ("\r\n");
590 sim_printf (" We highly recommend running the simulator as a non-privileged user.\r\n");
591 } else {
592 ++hint_count;
593 }
594 }
595 #endif
596
597
598
599
600 #if defined(TESTING)
601 if (!flag) {
602 sim_hrline ();
603 sim_printf ("\r\n* Hint #%u - TESTING BUILD DETECTED\r\n", ++hint_count);
604 sim_printf ("\r\n");
605 sim_printf (" You are running a TESTING build.\r\n");
606 sim_printf ("\r\n");
607 sim_printf (" TESTING builds intended strictly for development purposes.\r\n");
608 sim_printf ("\r\n");
609 sim_printf (" Reliability, stability, and performance will be adversely impacted.\r\n");
610 } else {
611 ++hint_count;
612 }
613 #endif
614
615
616
617
618 #if defined(WITH_ABSI_DEV) || defined(WITH_SOCKET_DEV)
619 if (!flag) {
620 sim_hrline ();
621 sim_printf ("\r\n* Hint #%u - UNSUPPORTED OR EXPERIMENTAL BUILD OPTIONS DETECTED\r\n", ++hint_count);
622 sim_printf ("\r\n");
623 sim_printf (" You are running a build with unsupported or experimental options enabled:\r\n");
624 sim_printf ("\r\n");
625 # if defined(WITH_ABSI_DEV)
626 sim_printf (" * WITH_ABSI_DEV is enabled.\r\n");
627 # endif
628 # if defined(WITH_SOCKET_DEV)
629 sim_printf (" * WITH_SOCKET_DEV is enabled.\r\n");
630 # endif
631 sim_printf ("\r\n");
632 sim_printf (" Reliability, stability, and performance will be adversely impacted.\r\n");
633 } else {
634 ++hint_count;
635 }
636 #endif
637
638
639
640
641 #if defined(__CYGWIN__)
642 if (!flag) {
643 sim_hrline ();
644 sim_printf ("\r\n* Hint #%u - CYGWIN WINDOWS BUILD DETECTED\r\n", ++hint_count);
645 sim_printf ("\r\n");
646 sim_printf (" You are using a Cygwin Windows build.\r\n");
647 sim_printf ("\r\n");
648 sim_printf (" The simulator supports native Windows builds (using the MinGW toolchain).\r\n");
649 sim_printf (" Unless you have a specific reason for using a Cygwin build, we recommend\r\n");
650 sim_printf (" using a native build instead, which has better performance for most users.\r\n");
651 } else {
652 ++hint_count;
653 }
654 #endif
655
656
657
658
659 if (check_scaling_governors ()) {
660 if (!flag) {
661 unsigned long long reduced = (unsigned long long)check_scaling_governors();
662 unsigned long long total = (unsigned long long)nprocs;
663 sim_hrline ();
664 sim_printf ("\r\n* Hint #%u - POWER-SAVING CPU GOVERNOR CONFIGURATION DETECTED\r\n", ++hint_count);
665 sim_printf ("\r\n");
666 if (total > reduced)
667 sim_printf(" You have %llu (out of %llu) processors using a power-saving governor.\r\n",
668 reduced, total);
669 else
670 sim_printf(" You have %llu logical processors configured using a power-saving governor.\r\n",
671 reduced);
672 } else {
673 ++hint_count;
674 }
675 }
676
677
678
679
680 #if defined(LOCKLESS)
681 if (nprocs < 2 && ncores < 2) {
682 if (!flag) {
683 sim_hrline ();
684 sim_printf ("\r\n* Hint #%u - UNIPROCESSOR HOST SYSTEM DETECTED\r\n", ++hint_count);
685 sim_printf ("\r\n");
686 sim_printf (" You seem to be running the simulator on a uniprocessor host system.\r\n");
687 sim_printf ("\r\n");
688 sim_printf (" The simulator supports a single-threaded build option (`NO_LOCKLESS`)\r\n");
689 sim_printf (" which may perform better on uniprocessor systems such as this one.\r\n");
690 } else {
691 ++hint_count;
692 }
693 }
694 #endif
695
696
697
698
699 #if defined(HAVE_LINEHISTORY) && !defined(_WIN32)
700 const char *term = getenv ("TERM");
701 if (NULL == term || 0 == strcmp (term, "dumb") || 0 == strcmp (term, "") || 0 == strcmp (term, "cons25")) {
702 if (!flag) {
703 sim_hrline ();
704 sim_printf ("\r\n* Hint #%u - TERM ENVIRONMENT VARIABLE SET TO UNSUPPORTED VALUE\r\n", ++hint_count);
705 sim_printf ("\r\n");
706 sim_printf (" The TERM environment variable is unset (or is set to an unsupported value).\r\n");
707 sim_printf ("\r\n");
708 sim_printf (" This disables the line-editing and history recall functionality of the\r\n");
709 sim_printf (" simulator shell. This is usually an unintentional misconfiguration.\r\n");
710 } else {
711 ++hint_count;
712 }
713 }
714 #endif
715
716
717
718
719 #if !defined(_WIN32) && !defined(__HAIKU__)
720 struct rlimit core_limit;
721 if (getrlimit(RLIMIT_CORE, &core_limit) == 0) {
722 if (core_limit.rlim_cur == 0) {
723 if (!flag) {
724 sim_hrline();
725 sim_printf("\r\n* Hint #%u - CORE DUMPS ARE DISABLED\r\n", ++hint_count);
726 sim_printf("\r\n");
727 sim_printf(" Core dumps are disabled. If the simulator crashes, it will not be able\r\n");
728 sim_printf(" to produce a core file, which can help determine the cause of the crash.\r\n");
729 sim_printf("\r\n");
730 sim_printf(" Try setting `ulimit -c unlimited` (or sometimes `ulimit -Hc unlimited`)\r\n");
731 sim_printf(" in your shell to remove this restriction.\r\n");
732 } else {
733 ++hint_count;
734 }
735 }
736 else if (core_limit.rlim_cur != RLIM_INFINITY) {
737 if (!flag) {
738 sim_hrline();
739 sim_printf("\r\n* Hint #%u - CORE DUMPS ARE RESTRICTED\r\n", ++hint_count);
740 sim_printf("\r\n");
741 sim_printf(" Core dumps are restricted. If the simulator crashes, it may not be able\r\n");
742 sim_printf(" to produce a core file, which can help determine the cause of the crash.\r\n");
743 sim_printf("\r\n");
744 sim_printf(" Your configuration is currently restricting core dumps to %llu KB.\r\n",
745 (unsigned long long)core_limit.rlim_cur / 1024);
746 sim_printf("\r\n");
747 sim_printf(" Try setting `ulimit -c unlimited` (or sometimes `ulimit -Hc unlimited`)\r\n");
748 sim_printf(" in your shell to remove this restriction.\r\n");
749 } else {
750 ++hint_count;
751 }
752 }
753 }
754 #endif
755
756
757
758
759 if (is_raspberry_pi ()) {
760 uint32_t a_issues;
761 if (check_cpu_frequencies()) {
762 if (!flag) {
763 sim_hrline ();
764 sim_printf ("\r\n* Hint #%u - RASPBERRY PI FIXED FREQUENCY CONFIGURATION\r\n", ++hint_count);
765 sim_printf ("\r\n");
766 sim_printf (" The simulator has detected it is running on a Raspberry Pi single-board\r\n");
767 sim_printf (" computer, which is not configured for fixed frequency operation.\r\n");
768 sim_printf (" Using a fixed-frequency configuration allows for more deterministic\r\n");
769 sim_printf (" response times and enhances performance and simulation fidelity.\r\n");
770 sim_printf ("\r\n");
771 sim_printf (" Use `cpupower frequency-info` (from the `linux-cpupower` package) to view\r\n");
772 sim_printf (" the current configuration, or `sudo cpupower frequency-set -f` to change\r\n");
773 sim_printf (" it, for example, `sudo cpupower frequency-set -f 1200Mhz`. Refer to the\r\n");
774 sim_printf (" documentation for your specific Raspberry Pi model for proper values.\r\n");
775 } else {
776 ++hint_count;
777 }
778 }
779 a_issues = check_pi_issues ();
780 if ( a_issues & (1 << 0) ||
781 #if defined(RPI_CAPPING)
782 a_issues & (1 << 1) ||
783 #endif
784 a_issues & (1 << 2) ||
785 a_issues & (1 << 3) ) {
786 if (!flag) {
787 sim_hrline ();
788 sim_printf ("\r\n* Hint #%u - RASPBERRY PI ADVERSE HARDWARE EVENTS RECORDED\r\n", ++hint_count);
789 sim_printf ("\r\n");
790 sim_printf (" Your Raspberry Pi has recorded the following adverse hardware event(s):\r\n");
791 sim_printf ("\r\n");
792 if (a_issues & (1 << 0))
793 sim_printf(" * Undervoltage events have occurred since boot.\r\n");
794 #if defined(RPI_CAPPING)
795 if (a_issues & (1 << 1))
796 sim_printf(" * CPU frequency capping events have occurred since boot.\r\n");
797 #endif
798 if (a_issues & (1 << 2))
799 sim_printf(" * Throttling events have occurred since boot.\r\n");
800 if (a_issues & (1 << 3))
801 sim_printf(" * Soft temperature limits have been reached or exceeded since boot.\r\n");
802 } else {
803 ++hint_count;
804 }
805 }
806 }
807
808
809
810
811 #if !defined(_WIN32) && !defined(FORCE_STATIC) && !defined(__FILC__)
812 if (1 < nprocs && false == dps8_topo_used && 1 != is_static_linked()) {
813 if (!flag) {
814 sim_hrline ();
815 sim_printf ("\r\n* Hint #%u - UNABLE TO DETERMINE SYSTEM TOPOLOGY USING LIBHWLOC\r\n", ++hint_count);
816 sim_printf ("\r\n");
817 sim_printf (" No overall topology information could be determined for this system.\r\n");
818 sim_printf (" The simulator is aware this system has %llu logical processors available,\r\n",
819 (unsigned long long)nprocs);
820 sim_printf (" but it was not able to determine the number of actual physical cores.\r\n");
821 sim_printf ("\r\n");
822 sim_printf (" The simulator uses topology information to optimize performance and\r\n");
823 sim_printf (" to warn about potentially dangerous or suboptimal configurations.\r\n");
824 sim_printf (" We use libhwloc (https://www-lb.open-mpi.org/projects/hwloc/) to query\r\n");
825 sim_printf (" this information in an architecture and operating system agnostic way.\r\n");
826 # if defined(__APPLE__)
827 sim_printf ("\r\n");
828 sim_printf (" On macOS, you can install the libhwloc library using the Homebrew\r\n");
829 sim_printf (" package manager (https://brew.sh/) by running `brew install hwloc`.\r\n");
830 # elif defined(__FreeBSD__)
831 sim_printf ("\r\n");
832 sim_printf (" On FreeBSD, you can install the hwloc from packages (`pkg install hwloc`)\r\n");
833 sim_printf (" or build from ports (`cd /usr/ports/devel/hwloc/ && make install clean`).\r\n");
834 # elif defined(__linux__)
835 sim_printf ("\r\n");
836 sim_printf (" Linux distributions usually provide this library as the `hwloc` package.\r\n");
837 # endif
838 sim_printf ("\r\n");
839 sim_printf (" No recompilation of the simulator is necessary for it to use libhwloc.\r\n");
840 } else {
841 ++hint_count;
842 }
843 }
844 #endif
845
846
847
848
849 #if defined(__linux__) && defined(CAP_SYS_NICE) && !defined(__ANDROID__)
850 const pid_t pid = _sir_getpid();
851 const int cap_sys_nice = CAP_SYS_NICE;
852
853 if (nprocs > 1 && !has_linux_capability(pid, cap_sys_nice)) {
854 if (!flag) {
855 sim_hrline ();
856 sim_printf ("\r\n* Hint #%u - LINUX REAL-TIME SCHEDULING CAPABILITY IS NOT ENABLED\r\n", ++hint_count);
857 sim_printf ("\r\n");
858 sim_printf (" Linux real-time scheduling capability is not enabled.\r\n");
859 sim_printf (" Real-time support allows for accurate and deterministic response times\r\n");
860 sim_printf (" and improved thread scheduling behavior, enhancing simulation fidelity.\r\n");
861 if (nprocs > 2) {
862 if ((unsigned long long)ncores > 1 && (unsigned long long)ncores != (unsigned long long)nprocs) {
863 sim_printf(" Since this system seems to have %llu logical (and %llu physical) processors,\r\n",
864 (unsigned long long)nprocs, (unsigned long long)ncores);
865 } else {
866 sim_printf(" Since this system seems to have at least %llu logical processors available,\r\n",
867 (unsigned long long)nprocs);
868 }
869 sim_printf (" the real-time mode (requested by the `-p` argument) may be considered.\r\n");
870 }
871 sim_printf ("\r\n");
872 sim_printf (" To enable the real-time capability, run the following shell command:\r\n");
873 sim_printf ("\r\n");
874 sim_printf (" sudo setcap 'cap_sys_nice,cap_ipc_lock+ep' %s\r\n", sim_appfilename);
875 } else {
876 ++hint_count;
877 }
878 }
879 #endif
880
881
882
883
884 #if !defined(__ANDROID__)
885 if (true == mlock_failure) {
886 if (!flag) {
887 sim_hrline ();
888 sim_printf ("\r\n* Hint #%u - UNABLE TO LOCK SIMULATOR MEMORY WITH MLOCK()\r\n", ++hint_count);
889 sim_printf ("\r\n");
890 sim_printf (" The simulator attempted, but failed, to use memory locking with mlock().\r\n");
891 sim_printf (" Memory locking prevents the simulated memory from being swapped out to\r\n");
892 sim_printf (" disk. This avoids page faults and enables more deterministic performance.\r\n");
893 sim_printf (" Memory locking also enhances response times for real-time mode operation.\r\n");
894 # if defined(__linux__) && defined(CAP_IPC_LOCK)
895 const pid_t pid = _sir_getpid();
896 const int cap_ipc_lock = CAP_IPC_LOCK;
897 if (!has_linux_capability(pid, cap_ipc_lock)) {
898 sim_printf ("\r\n");
899 sim_printf (" You can enable real-time and memory locking by running this shell command:\r\n");
900 sim_printf ("\r\n");
901 sim_printf (" sudo setcap 'cap_sys_nice,cap_ipc_lock+ep' %s\r\n", sim_appfilename);
902 }
903 # elif defined(__FreeBSD__)
904 sim_printf ("\r\n");
905 sim_printf (" See https://man.freebsd.org/cgi/man.cgi?login.conf(5) for details.\r\n");
906 # elif defined(__sun) || defined(__illumos__)
907 sim_printf ("\r\n");
908 sim_printf (" You can allow memory locking by running the following shell commands:\r\n");
909 sim_printf ("\r\n");
910 sim_printf (" sudo chown root:root %s\r\n", sim_appfilename);
911 sim_printf (" sudo chmod u+s %s\r\n", sim_appfilename);
912 sim_printf ("\r\n");
913 sim_printf (" This is safe - we drop all unnecessary privileges immediately at start-up.\r\n");
914 # else
915 sim_printf("\r\n");
916 sim_printf(" You can check `ulimit -l` in your shell to verify locking is unrestricted.\r\n");
917 # endif
918 } else {
919 ++hint_count;
920 }
921 }
922 #endif
923
924
925
926
927 #if defined(LOCKLESS) && !defined(__SUNPRO_C) && !defined(__SUNPRO_CC)
928 # define CHECK_LOCK_FREE(var, type_name, counter, names, index) \
929 do { \
930 if (!atomic_is_lock_free (&var)) { \
931 names[index] = type_name; \
932 index++; \
933 counter++; \
934 } \
935 } while (0)
936
937 atomic_uint_fast32_t af32_t = 0;
938 atomic_size_t asize_t = 0;
939 atomic_bool abool = 0;
940 atomic_int aint = 0;
941 atomic_long along = 0;
942 int *naptr;
943 atomic_uintptr_t aptr;
944
945 atomic_init (&aptr, (uintptr_t)&naptr);
946 (void)naptr;
947
948 const char *non_lock_free_names[6];
949 int non_lock_free_count = 0;
950 int index = 0;
951
952 CHECK_LOCK_FREE (af32_t, "atomic_uint_fast32_t",
953 non_lock_free_count, non_lock_free_names, index);
954 CHECK_LOCK_FREE (asize_t, "atomic_size_t",
955 non_lock_free_count, non_lock_free_names, index);
956 CHECK_LOCK_FREE (abool, "atomic_bool",
957 non_lock_free_count, non_lock_free_names, index);
958 CHECK_LOCK_FREE (aint, "atomic_int",
959 non_lock_free_count, non_lock_free_names, index);
960 CHECK_LOCK_FREE (along, "atomic_long",
961 non_lock_free_count, non_lock_free_names, index);
962 CHECK_LOCK_FREE (aptr, "atomic_uintptr_t",
963 non_lock_free_count, non_lock_free_names, index);
964
965 if (non_lock_free_count > 0) {
966 if (!flag) {
967 const char *count_str = atm_cwords (non_lock_free_count);
968 sim_hrline ();
969 sim_printf ("\r\n* Hint #%u - ATOMIC TYPES DO NOT SUPPORT LOCK-FREE OPERATION\r\n", ++hint_count);
970 sim_printf ("\r\n %s atomic type%s %s not lock-free on this system:\r\n\r\n",
971 count_str, (non_lock_free_count == 1) ? "" : "s",
972 (non_lock_free_count == 1) ? "is" : "are");
973 for (unsigned int i = 0; i < non_lock_free_count; i++)
974 sim_printf (" * %s\r\n", non_lock_free_names[i]);
975 sim_printf ("\r\n");
976 sim_printf (" Atomic operations are lock-free only if the CPU provides the appropriate\r\n");
977 sim_printf (" instructions and your compiler knows how to take advantage of them.\r\n");
978 sim_printf ("\r\n");
979 sim_printf (" You could try upgrading the compiler, but this is usually a hardware\r\n");
980 sim_printf (" limitation. When the CPU does not support atomic operations, they rely\r\n");
981 sim_printf (" on locking, which adversely impacts the performance of threaded programs.\r\n");
982 if (1 == nprocs) {
983 sim_printf ("\r\n");
984 sim_printf (" Since it seems this system only has a single processor, you should try\r\n");
985 sim_printf (" building the `NO_LOCKLESS` non-threaded simulator for better performance.\r\n");
986 }
987 } else {
988 ++hint_count;
989 }
990 }
991 #endif
992
993
994
995
996 #if defined(__APPLE__)
997 if (1 == processIsTranslated()) {
998 if (!flag) {
999 sim_hrline ();
1000 sim_printf ("\r\n* Hint #%u - APPLE ROSETTA BINARY TRANSLATION DETECTED\r\n", ++hint_count);
1001 sim_printf ("\r\n Rosetta is an x86_64 to ARM64 (Apple Silicon) binary translation process.\r\n");
1002 sim_printf ("\r\n");
1003 sim_printf (" This means that the simulator binary you are executing was not compiled\r\n");
1004 sim_printf (" for the native architecture of your system. Although fully functional\r\n");
1005 sim_printf (" performance will be significantly reduced. It is highly recommended to\r\n");
1006 sim_printf (" use a native Apple Silicon (ARM64) build of the simulator.\r\n");
1007 } else {
1008 ++hint_count;
1009 }
1010 }
1011 #endif
1012
1013
1014
1015
1016 if (sim_free_memory < 192000000 && sim_free_memory > 0) {
1017 if (!flag) {
1018 sim_hrline ();
1019 sim_printf ("\r\n* Hint #%u - LOW SYSTEM MEMORY DETECTED\r\n", ++hint_count);
1020 sim_printf ("\r\n");
1021 sim_printf (" Currently %llu MB of memory is available (%llu MB at process start-up).\r\n",
1022 ((long long unsigned)sim_memory_available() / 1000000),
1023 ((long long unsigned)sim_free_memory / 1000000));
1024 sim_printf ("\r\n");
1025 sim_printf (" We recommend a minimum of 192 MB of available physical system memory\r\n");
1026 sim_printf (" for optimum simulator performance. Additionally, memory locking is not\r\n");
1027 sim_printf (" attempted when less than 192 MB of memory is available at start-up time.\r\n");
1028 } else {
1029 ++hint_count;
1030 }
1031 }
1032
1033
1034
1035
1036 if (0 == is_ntp_sync()) {
1037 if (!flag) {
1038 sim_hrline ();
1039 sim_printf ("\r\n* Hint #%u - NO EXTERNAL CLOCK SYNCHRONIZATION DETECTED\r\n", ++hint_count);
1040 sim_printf ("\r\n");
1041 sim_printf (" The system is reporting that your clock is NOT externally synchronized.\r\n");
1042 sim_printf (" Accurate time synchronization is critical for proper simulator operation.\r\n");
1043 sim_printf (" This can usually be resolved by ensuring that NTP (Network Time Protocol)\r\n");
1044 sim_printf (" software (e.g. ntpd, chrony, timesyncd, etc.) is installed and configured.\r\n");
1045 if (is_jailed()) {
1046 sim_printf ("\r\n");
1047 sim_printf (" NOTE: The simulator is running in a BSD jail. The time synchronization\r\n");
1048 sim_printf (" daemon must be installed and configured on the host, and not in the jail.\r\n");
1049 }
1050 } else {
1051 ++hint_count;
1052 }
1053 }
1054
1055
1056
1057
1058 if (hint_count) {
1059 if (!flag) {
1060 sim_hrline ();
1061 if (getenv("DPS8M_NO_HINTS") == NULL) {
1062 sim_printf ("\r\n");
1063 sim_printf ("To disable hint notifications, set the environment variable `DPS8M_NO_HINTS=1`\r\n");
1064 }
1065 sim_printf ("\r\n");
1066 } else {
1067 sim_printf("There %s %d %s available; use \"%s\" to view %s.\r\n\r\n",
1068 (hint_count == 1) ? "is" : "are", hint_count, (hint_count == 1) ? "hint" : "hints",
1069 (hint_count == 1) ? "SHOW HINT" : "SHOW HINTS", (hint_count == 1) ? "it" : "them");
1070 }
1071 } else {
1072 if (!flag) {
1073 sim_printf ("No hints are currently available.\r\n");
1074 }
1075 }
1076
1077 return 0;
1078 }