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