root/src/simh/sim_hints.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sim_hrline
  2. is_jailed
  3. is_static_linked_selfelf
  4. is_static_linked_selfmap
  5. is_static_linked
  6. is_ntp_sync
  7. has_linux_capability
  8. check_cpu_frequencies
  9. is_raspberry_pi
  10. check_pi_issues
  11. check_scaling_governors
  12. atm_cwords
  13. processIsTranslated
  14. show_hints

   1 /*
   2  * sim_hints.c: configuration hints
   3  *
   4  * vim: filetype=c:tabstop=2:ai:expandtab
   5  * SPDX-License-Identifier: ICU
   6  * scspell-id: 1784dba8-00a2-11f0-b624-80ee73e9b8e7
   7  *
   8  * ---------------------------------------------------------------------------
   9  *
  10  * Copyright (c) 2026 Eric Swenson
  11  * Copyright (c) 2026 Jeffrey H. Johnson
  12  * Copyright (c) 2026 The DPS8M Development Team
  13  *
  14  * This software is made available under the terms of the ICU License.
  15  * See the LICENSE.md file at the top-level directory of this distribution.
  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> // XXX: Check DragonFly
  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  * We may run in early startup (before logging has been initialized),
  63  * so only use non-logging libsir calls from functions in this file.
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138   sim_printf("\r\n------------------------------------------------------------------------------\r\n");
 139 }
 140 
 141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 142 
 143 static int
 144 is_jailed(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 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) //-V547
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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) { //-V560
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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) // -1 == Failed to check     0 == Not synchronized
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {                  //  1 == Maybe synchronized  2 == Synchronized OK
 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); // XXX: DragonFly?
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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'; //-NLOK
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* if defined(_APPLE_) */
 554 
 555 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 556 
 557 t_stat
 558 show_hints (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 559 {
 560   /* NOTE: We override the use of flag to enable early startup mode */
 561 
 562   hint_count = 0;
 563 
 564 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 565 /* HINT: Check if time_t is less than 64-bit and recommend mitigations. */
 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 /* HINT: Check if running as root and recommend not doing that. */
 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 /* HINT: Check for TESTING build and warn about it. */
 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 /* HINT: Check if we are running with unsupported or experimental build options enabled. */
 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 /* HINT: Check if we are running on Cygwin, and recommend using a native build instead. */
 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 /* HINT: Check that we are not using a power-saving CPU governor configuration. */
 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 /* HINT: Check if we are running a threaded simulator on a uniprocessor system. */
 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 /* HINT: Check for deficient TERM values. */
 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 /* HINT: Check that core dumps have not been limited or disabled. */
 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 /* HINT: Check if running on a suboptimally configured Raspberry Pi board. */
 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 /* HINT: Check if topology information was available, recommend installing libhwloc if not. */
 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 /* HINT: On Linux, check if we have real-time is allowed via capabilities. */
 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 /* HINT: Check if mlock failed to work and tell the user how to fix it. */
 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 /* HINT: Check if atomic types are not lock-free and warn the user about it. */
 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 /* HINT: Check for Apple Rosetta binary translation. */
 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 /* HINT: Check available memory and warn the user if it seems too low. */
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 /* HINT: Check for lack of external clock synchronization (like NTP). */
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 /* Hint notifications */
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 }

/* [previous][next][first][last][top][bottom][index][help] */