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

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