[BOLT] Add option instrumentation-max-size for bump allocator (#174716)

While the current max memory size is sufficient for most binaries, a few
binaries may encouter insufficient allocated memory space.

Allow specify the max memory size of the instrumentation bump allocator.
diff --git a/bolt/lib/Passes/Instrumentation.cpp b/bolt/lib/Passes/Instrumentation.cpp
index 150461b..97eae61 100644
--- a/bolt/lib/Passes/Instrumentation.cpp
+++ b/bolt/lib/Passes/Instrumentation.cpp
@@ -51,6 +51,12 @@
              "accuracy (for debugging, default: false)"),
     cl::init(false), cl::Optional, cl::cat(BoltInstrCategory));
 
+cl::opt<uint32_t> InstrumentationMaxSize(
+    "instrumentation-max-size",
+    cl::desc("Set max memory size of the instrumentation bump allocator "
+             "default: 0x6400000)"),
+    cl::init(0x6400000), cl::Optional, cl::cat(BoltInstrCategory));
+
 cl::opt<uint32_t> InstrumentationSleepTime(
     "instrumentation-sleep-time",
     cl::desc("interval between profile writes (default: 0 = write only at "
diff --git a/bolt/lib/RuntimeLibs/InstrumentationRuntimeLibrary.cpp b/bolt/lib/RuntimeLibs/InstrumentationRuntimeLibrary.cpp
index d6d6ebe..bca3c44 100644
--- a/bolt/lib/RuntimeLibs/InstrumentationRuntimeLibrary.cpp
+++ b/bolt/lib/RuntimeLibs/InstrumentationRuntimeLibrary.cpp
@@ -33,6 +33,7 @@
 extern cl::opt<bool> ConservativeInstrumentation;
 extern cl::opt<std::string> InstrumentationFilename;
 extern cl::opt<std::string> InstrumentationBinpath;
+extern cl::opt<uint32_t> InstrumentationMaxSize;
 extern cl::opt<uint32_t> InstrumentationSleepTime;
 extern cl::opt<bool> InstrumentationNoCountersClear;
 extern cl::opt<bool> InstrumentationWaitForks;
@@ -167,6 +168,7 @@
     emitFill(sizeof(uint64_t), Label);
 
   emitPadding(BC.RegularPageSize);
+  emitIntValue("__bolt_instr_max_size", opts::InstrumentationMaxSize);
   emitIntValue("__bolt_instr_sleep_time", opts::InstrumentationSleepTime);
   emitIntValue("__bolt_instr_no_counters_clear",
                !!opts::InstrumentationNoCountersClear, 1);
diff --git a/bolt/runtime/instr.cpp b/bolt/runtime/instr.cpp
index f586db2..c0b8fc3 100644
--- a/bolt/runtime/instr.cpp
+++ b/bolt/runtime/instr.cpp
@@ -85,6 +85,8 @@
 extern uint32_t __bolt_instr_num_funcs;
 // Time to sleep across dumps (when we write the fdata profile to disk)
 extern uint32_t __bolt_instr_sleep_time;
+// Max size of bump allocator
+extern uint32_t __bolt_instr_max_size;
 // Do not clear counters across dumps, rewrite file with the updated values
 extern bool __bolt_instr_no_counters_clear;
 // Wait until all forks of instrumented process will finish
@@ -1551,14 +1553,14 @@
   ret = __ftruncate(FD, 0);
   assert(ret == 0, "Failed to ftruncate!");
   BumpPtrAllocator HashAlloc;
-  HashAlloc.setMaxSize(0x6400000);
+  HashAlloc.setMaxSize(__bolt_instr_max_size);
   ProfileWriterContext Ctx = readDescriptions(LibContents, LibSize);
   Ctx.CallFlowTable = new (HashAlloc, 0) CallFlowHashTable(HashAlloc);
 
   DEBUG(printStats(Ctx));
 
   BumpPtrAllocator Alloc;
-  Alloc.setMaxSize(0x6400000);
+  Alloc.setMaxSize(__bolt_instr_max_size);
   const uint8_t *FuncDesc = Ctx.FuncDescriptions;
   for (int I = 0, E = __bolt_instr_num_funcs; I < E; ++I) {
     FuncDesc = writeFunctionProfile(FD, Ctx, FuncDesc, Alloc);
@@ -1662,8 +1664,9 @@
          "__bolt_instr_setup: failed to mmap page for metadata!");
 
   GlobalAlloc = new (GlobalMetadataStorage) BumpPtrAllocator;
-  // Conservatively reserve 100MiB
-  GlobalAlloc->setMaxSize(0x6400000);
+  // The max memory size can be set by -instrumentation-max-size, the default
+  // is 100MiB.
+  GlobalAlloc->setMaxSize(__bolt_instr_max_size);
   GlobalAlloc->setShared(Shared);
   GlobalWriteProfileMutex = new (*GlobalAlloc, 0) Mutex();
   if (__bolt_instr_num_ind_calls > 0)