Skip to content

Commit 03f47e8

Browse files
committed
Revert "compiler/rts: prelink archive threshold"
This reverts commit d821074.
1 parent d821074 commit 03f47e8

File tree

6 files changed

+1
-268
lines changed

6 files changed

+1
-268
lines changed

compiler/GHC/Driver/DynFlags.hs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,6 @@ data DynFlags = DynFlags {
196196

197197
enableTimeStats :: Bool, -- ^ Enable RTS timing statistics?
198198
ghcHeapSize :: Maybe Int, -- ^ The heap size to set.
199-
-- | Threshold (in bytes) above which GHCi will pre-link archives (ld -r)
200-
-- before loading. A value of 0 disables pre-linking.
201-
ghciPrelinkArchiveThreshold :: Maybe Integer,
202199

203200
maxRelevantBinds :: Maybe Int, -- ^ Maximum number of bindings from the type envt
204201
-- to show in type error messages
@@ -586,7 +583,6 @@ defaultDynFlags mySettings =
586583

587584
enableTimeStats = False,
588585
ghcHeapSize = Nothing,
589-
ghciPrelinkArchiveThreshold = Nothing,
590586

591587
importPaths = ["."],
592588
mainModuleNameIs = mAIN_NAME,

compiler/GHC/Driver/Session.hs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,6 @@ import qualified Data.Map as Map
295295
import qualified Data.Set as Set
296296
import Data.Word
297297
import System.FilePath
298-
-- no env tweaks needed here
299-
import Data.Int (Int64)
300298
import Text.ParserCombinators.ReadP hiding (char)
301299
import Text.ParserCombinators.ReadP as R
302300

@@ -886,7 +884,7 @@ parseDynamicFlagsFull activeFlags cmdline logger dflags0 args = do
886884
map ((rdr . ppr . getLoc &&& unLoc) . errMsg) $ errs
887885

888886
-- check for disabled flags in safe haskell
889-
let (dflags2, sh_warns) = safeFlagCheck cmdline dflags1
887+
let (dflags2, sh_warns) = safeFlagCheck cmdline dflags1
890888
theWays = ways dflags2
891889

892890
unless (allowed_combination theWays) $ liftIO $
@@ -901,10 +899,6 @@ parseDynamicFlagsFull activeFlags cmdline logger dflags0 args = do
901899
Just x -> liftIO (setHeapSize x)
902900
_ -> return ()
903901

904-
case ghciPrelinkArchiveThreshold dflags3 of
905-
Just n -> liftIO (setGhciPrelinkArchiveThreshold (fromIntegral (n :: Integer)))
906-
_ -> return ()
907-
908902
liftIO $ setUnsafeGlobalDynFlags dflags3
909903

910904
-- create message envelopes using final DynFlags: #23402
@@ -1081,8 +1075,6 @@ dynamic_flags_deps = [
10811075
-- RTS options -------------------------------------------------------------
10821076
, make_ord_flag defFlag "H" (HasArg (\s -> upd (\d ->
10831077
d { ghcHeapSize = Just $ fromIntegral (decodeSize s)})))
1084-
, make_ord_flag defGhcFlag "ghci-prelink-archive-threshold"
1085-
(HasArg (\s -> upd (\d -> d { ghciPrelinkArchiveThreshold = Just (decodeSize s) })))
10861078

10871079
, make_ord_flag defFlag "Rghc-timing" (NoArg (upd (\d ->
10881080
d { enableTimeStats = True })))
@@ -3816,7 +3808,6 @@ decodeSize str
38163808

38173809
foreign import ccall unsafe "setHeapSize" setHeapSize :: Int -> IO ()
38183810
foreign import ccall unsafe "enableTimingStats" enableTimingStats :: IO ()
3819-
foreign import ccall unsafe "setGhciPrelinkArchiveThreshold" setGhciPrelinkArchiveThreshold :: Int64 -> IO ()
38203811

38213812
outputFile :: DynFlags -> Maybe String
38223813
outputFile dflags

compiler/cbits/cutils.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ places in the GHC library.
77

88
#include <HsFFI.h>
99

10-
/* Prototype for FFI-callable helper */
11-
void enableTimingStats( void );
12-
void setHeapSize( HsInt size );
13-
void setGhciPrelinkArchiveThreshold( HsInt64 bytes );
14-
1510
void
1611
enableTimingStats( void ) /* called from the driver */
1712
{
@@ -27,10 +22,3 @@ setHeapSize( HsInt size )
2722
RtsFlags.GcFlags.maxHeapSize = RtsFlags.GcFlags.heapSizeSuggestion;
2823
}
2924
}
30-
31-
/* Configure GHCi pre-link archive threshold (in bytes). 0 disables. */
32-
void
33-
setGhciPrelinkArchiveThreshold( HsInt64 bytes )
34-
{
35-
RtsFlags.MiscFlags.linkerPrelinkArchiveThreshold = (StgInt64) bytes;
36-
}

rts/Linker.c

Lines changed: 0 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
#include "PathUtils.h"
3636
#include "CheckUnload.h" // createOCSectionIndices
3737
#include "ReportMemoryMap.h"
38-
#include "xxhash.h"
3938

4039
#if !defined(mingw32_HOST_OS) && defined(HAVE_SIGNAL_H)
4140
#include "posix/Signals.h"
@@ -445,176 +444,6 @@ void initLinker (void)
445444
initLinker_(1);
446445
}
447446

448-
// Helper to pre-link big archives into a temporary object file so the
449-
// internal linker can load a single .o instead of many members.
450-
#if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
451-
#include <errno.h>
452-
#include <sys/stat.h>
453-
#include <sys/types.h>
454-
#include <limits.h>
455-
#include <time.h>
456-
457-
static const char *ghci_basename_posix(const char *p)
458-
{
459-
const char *last = p;
460-
if (!p) return p;
461-
for (const char *s = p; *s; ++s) {
462-
if (*s == '/') last = s + 1;
463-
}
464-
return last;
465-
}
466-
467-
static const char *ghci_tmpdir(void)
468-
{
469-
const char *t = getenv("TMPDIR");
470-
return t && *t ? t : "/tmp";
471-
}
472-
473-
static bool ghci_read_file_prefix(const char *path, char *buf, size_t bufsz)
474-
{
475-
FILE *f = fopen(path, "rb");
476-
if (!f) return false;
477-
size_t n = fread(buf, 1, bufsz - 1, f);
478-
buf[n] = '\0';
479-
fclose(f);
480-
return true;
481-
}
482-
483-
static bool ghci_compute_cache_key(const char *path, char out_hex[65])
484-
{
485-
FILE *f = fopen(path, "rb");
486-
if (!f) return false;
487-
XXH64_state_t* st = XXH64_createState();
488-
if (!st) { fclose(f); return false; }
489-
if (XXH64_reset(st, 0) != XXH_OK) { XXH64_freeState(st); fclose(f); return false; }
490-
unsigned char buf[256 * 1024];
491-
size_t n;
492-
while ((n = fread(buf, 1, sizeof(buf), f)) > 0) {
493-
if (XXH64_update(st, buf, n) != XXH_OK) {
494-
XXH64_freeState(st); fclose(f); return false;
495-
}
496-
}
497-
fclose(f);
498-
XXH64_hash_t hv = XXH64_digest(st);
499-
XXH64_freeState(st);
500-
// render as 16-char hex (zero-padded)
501-
// use unsigned long long to satisfy printf on most platforms
502-
unsigned long long v = (unsigned long long)hv;
503-
// ensure buffer large enough; we reserved 65 earlier
504-
snprintf(out_hex, 65, "%016llx", v);
505-
return true;
506-
}
507-
508-
static pathchar *ghci_prelink_archive_to_tmp(pathchar *archivePath, size_t threshold)
509-
{
510-
struct_stat st;
511-
if (pathstat(archivePath, &st) != 0) return NULL;
512-
if (threshold == 0 || (size_t)st.st_size < threshold) return NULL;
513-
514-
// Build cache target name using SHA-256 and include basename for readability
515-
char hex[65];
516-
if (!ghci_compute_cache_key((const char *)archivePath, hex)) {
517-
return NULL;
518-
}
519-
520-
const char *tmpdir = ghci_tmpdir();
521-
const char *base = ghci_basename_posix((const char *)archivePath);
522-
int target_needed = snprintf(NULL, 0, "%s/ghc-prelink-%s-%s.o", tmpdir, base, hex);
523-
pathchar *target = stgMallocBytes((target_needed + 1) * pathsize, "ghci_prelink(target)");
524-
snprintf((char *)target, target_needed + 1, "%s/ghc-prelink-%s-%s.o", tmpdir, base, hex);
525-
526-
// If cached object exists, use it
527-
struct stat sb;
528-
if (stat((const char *)target, &sb) == 0 && sb.st_size > 0) {
529-
return target;
530-
}
531-
532-
// Cross-process lock using a directory
533-
char lock_path[PATH_MAX];
534-
snprintf(lock_path, sizeof(lock_path), "%s/ghc-prelink-%s-%s.building", tmpdir, base, hex);
535-
if (mkdir(lock_path, 0700) == 0) {
536-
// We are the builder
537-
int tmp_needed = snprintf(NULL, 0, "%s/ghc-prelink-%d-%s.tmp.o", tmpdir, (int)getpid(), base);
538-
pathchar *tmp_out = stgMallocBytes((tmp_needed + 1) * pathsize, "ghci_prelink(tmp)");
539-
snprintf((char *)tmp_out, tmp_needed + 1, "%s/ghc-prelink-%d-%s.tmp.o", tmpdir, (int)getpid(), base);
540-
541-
// Log for diagnostics
542-
char log_path[PATH_MAX];
543-
snprintf(log_path, sizeof(log_path), "%s/ghc-prelink-%s.log", tmpdir, hex);
544-
545-
const char *cc = getenv("CC");
546-
if (!cc || !*cc) cc = "cc";
547-
const char *ldflags = getenv("LDFLAGS");
548-
if (!ldflags) ldflags = "";
549-
char cmd[4096];
550-
# if defined(OBJFORMAT_ELF)
551-
int n = snprintf(cmd, sizeof(cmd),
552-
"%s %s -nostdlib -Wl,-r -Wl,--whole-archive '%s' -Wl,--no-whole-archive -o '%s' >'%s' 2>&1",
553-
cc, ldflags, (const char *)archivePath, (const char *)tmp_out, log_path);
554-
# elif defined(OBJFORMAT_MACHO)
555-
int n = snprintf(cmd, sizeof(cmd),
556-
"%s %s -nostdlib -Wl,-r -Wl,-all_load '%s' -o '%s' >'%s' 2>&1",
557-
cc, ldflags, (const char *)archivePath, (const char *)tmp_out, log_path);
558-
# endif
559-
if (n < 0 || (size_t)n >= sizeof(cmd)) {
560-
errorBelch("prelink: command too long while building cache for %s", base);
561-
stgFree(tmp_out);
562-
rmdir(lock_path);
563-
stgFree(target);
564-
return NULL;
565-
}
566-
567-
IF_DEBUG(linker, debugBelch("prelinking large archive: %" PATH_FMT " -> %s (cc=%s)\n", archivePath, (char *)tmp_out, cc));
568-
int rc = system(cmd);
569-
if (rc != 0) {
570-
char buf[1024];
571-
buf[0] = '\0';
572-
if (ghci_read_file_prefix(log_path, buf, sizeof(buf))) {
573-
errorBelch("prelink failed (rc=%d) for %s; command: %s\n%s", rc, base, cmd, buf);
574-
} else {
575-
errorBelch("prelink failed (rc=%d) for %s; command: %s", rc, base, cmd);
576-
}
577-
unlink((const char *)tmp_out);
578-
unlink(log_path);
579-
rmdir(lock_path);
580-
stgFree(tmp_out);
581-
stgFree(target);
582-
return NULL;
583-
}
584-
585-
// Atomically move into place
586-
if (rename((const char *)tmp_out, (const char *)target) != 0) {
587-
errorBelch("prelink: failed to rename '%s' to '%s' (errno=%d)", (char *)tmp_out, (char *)target, errno);
588-
unlink((const char *)tmp_out);
589-
unlink(log_path);
590-
rmdir(lock_path);
591-
stgFree(tmp_out);
592-
stgFree(target);
593-
return NULL;
594-
}
595-
unlink(log_path);
596-
rmdir(lock_path);
597-
stgFree(tmp_out);
598-
return target;
599-
} else {
600-
// Someone else is building; wait for target to appear
601-
const int max_ms = 30000; // 30 seconds
602-
int waited = 0;
603-
while (waited < max_ms) {
604-
if (stat((const char *)target, &sb) == 0 && sb.st_size > 0) {
605-
return target;
606-
}
607-
struct timespec ts = {0, 100 * 1000 * 1000}; // 100ms
608-
nanosleep(&ts, NULL);
609-
waited += 100;
610-
}
611-
// Give up
612-
stgFree(target);
613-
return NULL;
614-
}
615-
}
616-
#endif
617-
618447
void
619448
initLinker_ (int retain_cafs)
620449
{
@@ -1639,55 +1468,9 @@ static HsInt loadObj_ (pathchar *path)
16391468
return 1; // success
16401469
}
16411470

1642-
// Optionally pre-link large archives into a temporary .o to speed up loading.
1643-
// Runtime configuration precedence:
1644-
// 1) +RTS --linker-prelink-archive-threshold=<size>
1645-
// 2) env GHCI_PRELINK_ARCHIVE_THRESHOLD=<size>
1646-
// 3) default 100M
1647-
static size_t ghci_prelink_threshold = (size_t)-1;
1648-
if (ghci_prelink_threshold == (size_t)-1) {
1649-
// Env var takes precedence over the RTS field
1650-
size_t val;
1651-
const char *env = getenv("GHCI_PRELINK_ARCHIVE_THRESHOLD");
1652-
if (env && *env) {
1653-
char *endp = NULL;
1654-
unsigned long long n = strtoull(env, &endp, 10);
1655-
if (endp && (*endp == 'K' || *endp == 'k')) {
1656-
val = (size_t)n * 1024ULL;
1657-
} else if (endp && (*endp == 'M' || *endp == 'm')) {
1658-
val = (size_t)n * 1024ULL * 1024ULL;
1659-
} else if (endp && (*endp == 'G' || *endp == 'g')) {
1660-
val = (size_t)n * 1024ULL * 1024ULL * 1024ULL;
1661-
} else {
1662-
val = (size_t)n;
1663-
}
1664-
} else {
1665-
// use the RTS field (set by +RTS or defaulted)
1666-
val = (size_t)RtsFlags.MiscFlags.linkerPrelinkArchiveThreshold;
1667-
}
1668-
ghci_prelink_threshold = val;
1669-
}
1670-
16711471
// Things that look like object files (e.g. end in `.o`) may nevertheless be
16721472
// archives, as noted in Note [Object merging] in GHC.Driver.Pipeline.Execute.
16731473
if (isArchive(path)) {
1674-
// Try pre-linking if the archive is large enough
1675-
pathchar *tmp_o = NULL;
1676-
#if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
1677-
tmp_o = ghci_prelink_archive_to_tmp(path, ghci_prelink_threshold);
1678-
#endif
1679-
if (tmp_o != NULL) {
1680-
HsInt ok = loadObj_(tmp_o);
1681-
if (!ok) {
1682-
IF_DEBUG(linker, debugBelch("prelinked loading failed for %" PATH_FMT ", falling back to archive loader\n", path));
1683-
// Fall back to archive loader
1684-
stgFree(tmp_o);
1685-
} else {
1686-
// Keep the temp file on disk to allow later unload/debug. Do not free oc->fileName here.
1687-
stgFree(tmp_o);
1688-
return 1;
1689-
}
1690-
}
16911474
if (loadArchive_(path)) {
16921475
return 1; // success
16931476
} else {

rts/RtsFlags.c

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,6 @@ void initRtsFlagsDefaults(void)
272272
RtsFlags.MiscFlags.linkerOptimistic = false;
273273
RtsFlags.MiscFlags.linkerMemBase = 0;
274274
RtsFlags.MiscFlags.ioManager = IO_MNGR_FLAG_AUTO;
275-
/* Default to 100 MiB; can be overridden by env or +RTS */
276-
RtsFlags.MiscFlags.linkerPrelinkArchiveThreshold = (int64_t)(100ULL * 1024ULL * 1024ULL);
277275
#if defined(THREADED_RTS) && defined(mingw32_HOST_OS)
278276
RtsFlags.MiscFlags.numIoWorkerThreads = getNumberOfProcessors();
279277
#else
@@ -557,9 +555,6 @@ usage_text[] = {
557555
" -xm Base address to mmap memory in the GHCi linker",
558556
" (hex; must be <80000000)",
559557
#endif
560-
" --linker-prelink-archive-threshold=<size>",
561-
" Pre-link large .a archives to a temporary .o before loading.",
562-
" Units: K, M, G. 0 disables. Default: 100M (if not set via env)",
563558
" -xq The allocation limit given to a thread after it receives",
564559
" an AllocationLimitExceeded exception. (default: 100k)",
565560
"",
@@ -1010,24 +1005,6 @@ error = true;
10101005
OPTION_UNSAFE;
10111006
RtsFlags.MiscFlags.linkerOptimistic = true;
10121007
}
1013-
else if (!strncmp("linker-prelink-archive-threshold=",
1014-
&rts_argv[arg][2], 33)) {
1015-
OPTION_UNSAFE;
1016-
/* rts_argv[arg] is like "--linker-prelink-archive-threshold=<size>" */
1017-
/* The value begins after the '=' which is at index 36 of the string */
1018-
/* We can't easily compute the offset robustly from here; instead find '=' */
1019-
const char* full = rts_argv[arg];
1020-
const char* eq = strchr(full, '=');
1021-
if (eq == NULL) {
1022-
errorBelch("%s: missing value", rts_argv[arg]);
1023-
error = true;
1024-
} else {
1025-
/* decodeSize expects the full flag and an offset to the value within it */
1026-
uint32_t off = (uint32_t)(eq - full + 1);
1027-
StgWord64 bytes = decodeSize(full, off, 0, HS_WORD64_MAX);
1028-
RtsFlags.MiscFlags.linkerPrelinkArchiveThreshold = (int64_t)bytes;
1029-
}
1030-
}
10311008
else if (strequal("null-eventlog-writer",
10321009
&rts_argv[arg][2])) {
10331010
OPTION_UNSAFE;

rts/include/rts/Flags.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,6 @@ typedef struct _MISC_FLAGS {
272272
* for the linker, NULL ==> off */
273273
IO_MANAGER_FLAG ioManager; /* The I/O manager to use. */
274274
uint32_t numIoWorkerThreads; /* Number of I/O worker threads to use. */
275-
/* Pre-link large archives before loading into the RTS linker. */
276-
int64_t linkerPrelinkArchiveThreshold; /* bytes; default set in RtsFlags; 0 = disable */
277275
} MISC_FLAGS;
278276

279277
/* See Note [Synchronization of flags and base APIs] */

0 commit comments

Comments
 (0)