* gold.cc (queue_initial_tasks): Pass incremental base filename
authorCary Coutant <ccoutant@google.com>
Tue, 24 May 2011 23:31:07 +0000 (23:31 +0000)
committerCary Coutant <ccoutant@google.com>
Tue, 24 May 2011 23:31:07 +0000 (23:31 +0000)
to Output_file::open_base_file; don't print error message.
* incremental-dump.cc (main): Adjust call to
Output_file::open_for_modification.
* incremental-dump.cc (main): Likewise.
* incremental.cc (Incremental_inputs::report_command_line):
Ignore --incremental-base option when comparing command lines.
Ignore parameter when given as separate argument.
* options.h (class General_options): Add --incremental-base.
* output.cc (Output_file::Output_file):
(Output_file::open_base_file): Add base_name and writable parameters;
read base file into new file; print error message here.
(Output_file::map_no_anonymous): Add writable parameter; adjust all
callers.
* output.h (Output_file::open_for_modification): Rename to...
(Output_file::open_base_file): ...this; add base_name and
writable parameters; adjust all callers.
(Output_file::map_no_anonymous): Add writable parameter; adjust all
callers.
* testsuite/Makefile.am (incremental_test_4): Test
--incremental-base.
* testsuite/Makefile.in: Regenerate.

gold/ChangeLog
gold/gold.cc
gold/incremental-dump.cc
gold/incremental.cc
gold/options.h
gold/output.cc
gold/output.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in

index bce6bc8504a718c2868c2615d34954ce99ece06b..12463516dc77ae4b3414bcf986a01bbb76dbe68b 100644 (file)
@@ -1,3 +1,28 @@
+2011-05-24 Cary Coutant  <ccoutant@google.com>
+
+       * gold.cc (queue_initial_tasks): Pass incremental base filename
+       to Output_file::open_base_file; don't print error message.
+       * incremental-dump.cc (main): Adjust call to
+       Output_file::open_for_modification.
+       * incremental-dump.cc (main): Likewise.
+       * incremental.cc (Incremental_inputs::report_command_line):
+       Ignore --incremental-base option when comparing command lines.
+       Ignore parameter when given as separate argument.
+       * options.h (class General_options): Add --incremental-base.
+       * output.cc (Output_file::Output_file):
+       (Output_file::open_base_file): Add base_name and writable parameters;
+       read base file into new file; print error message here.
+       (Output_file::map_no_anonymous): Add writable parameter; adjust all
+       callers.
+       * output.h (Output_file::open_for_modification): Rename to...
+       (Output_file::open_base_file): ...this; add base_name and
+       writable parameters; adjust all callers.
+       (Output_file::map_no_anonymous): Add writable parameter; adjust all
+       callers.
+       * testsuite/Makefile.am (incremental_test_4): Test
+       --incremental-base.
+       * testsuite/Makefile.in: Regenerate.
+
 2011-05-24 Cary Coutant  <ccoutant@google.com>
 
        * testsuite/Makefile.am: Add incremental_test_2, incremental_test_3,
index bf5ac89929807c6b0b2f9ae5f3ef6f1e1398e15f..4f1f871250ed539e77949d54457edf087f2f4668 100644 (file)
@@ -204,11 +204,7 @@ queue_initial_tasks(const General_options& options,
       if (parameters->incremental_update())
        {
          Output_file* of = new Output_file(options.output_file_name());
-         if (!of->open_for_modification())
-           gold_info(_("incremental update not possible: "
-                       "cannot open %s"),
-                     options.output_file_name());
-         else
+         if (of->open_base_file(options.incremental_base(), true))
            {
              ibase = open_incremental_binary(of);
              if (ibase != NULL
index 1887db86cac6c30837f3854736bbb8dc193e85a9..a727eb5038437072e1618fe0c02df8750ff8b66c 100644 (file)
@@ -449,10 +449,10 @@ main(int argc, char** argv)
 
   Output_file* file = new Output_file(filename);
 
-  bool t = file->open_for_modification();
+  bool t = file->open_base_file(NULL, false);
   if (!t)
     {
-      fprintf(stderr, "%s: open_for_modification(%s): %s\n", argv[0], filename,
+      fprintf(stderr, "%s: open_base_file(%s): %s\n", argv[0], filename,
               strerror(errno));
       return 1;
     }
index 0a8994078f9029e48be308fc81b1c95fe1d4fcb4..a27afeef1c91e14846dc97b5c758f501fc2ef355 100644 (file)
@@ -861,8 +861,17 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv)
          || strcmp(argv[i], "--incremental-changed") == 0
          || strcmp(argv[i], "--incremental-unchanged") == 0
          || strcmp(argv[i], "--incremental-unknown") == 0
+         || is_prefix_of("--incremental-base=", argv[i])
          || is_prefix_of("--debug=", argv[i]))
         continue;
+      if (strcmp(argv[i], "--incremental-base") == 0
+         || strcmp(argv[i], "--debug") == 0)
+       {
+         // When these options are used without the '=', skip the
+         // following parameter as well.
+         ++i;
+         continue;
+       }
 
       args.append(" '");
       // Now append argv[i], but with all single-quotes escaped
index f98bb27ba88f4e55de3e296057f0b6e124aacf91..b3b51dc67ec3c381f3fa45c4720bccde9fb976db 100644 (file)
@@ -787,6 +787,11 @@ class General_options
   DEFINE_special(incremental_update, options::TWO_DASHES, '\0',
                 N_("Do an incremental link; exit if not possible"), NULL);
 
+  DEFINE_string(incremental_base, options::TWO_DASHES, '\0', NULL,
+                N_("Set base file for incremental linking"
+                   " (default is output file)"),
+                N_("FILE"));
+
   DEFINE_special(incremental_changed, options::TWO_DASHES, '\0',
                  N_("Assume files changed"), NULL);
 
index 6555830fe9ef9727ef0715d3dbafc1f3d389fe82..b3fd35d671cd4f098e056412a360b6d3d2a111cb 100644 (file)
@@ -4562,31 +4562,77 @@ Output_file::Output_file(const char* name)
 }
 
 // Try to open an existing file.  Returns false if the file doesn't
-// exist, has a size of 0 or can't be mmapped.
+// exist, has a size of 0 or can't be mmapped.  If BASE_NAME is not
+// NULL, open that file as the base for incremental linking, and
+// copy its contents to the new output file.  This routine can
+// be called for incremental updates, in which case WRITABLE should
+// be true, or by the incremental-dump utility, in which case
+// WRITABLE should be false.
 
 bool
-Output_file::open_for_modification()
+Output_file::open_base_file(const char* base_name, bool writable)
 {
   // The name "-" means "stdout".
   if (strcmp(this->name_, "-") == 0)
     return false;
 
+  bool use_base_file = base_name != NULL;
+  if (!use_base_file)
+    base_name = this->name_;
+  else if (strcmp(base_name, this->name_) == 0)
+    gold_fatal(_("%s: incremental base and output file name are the same"),
+              base_name);
+
   // Don't bother opening files with a size of zero.
   struct stat s;
-  if (::stat(this->name_, &s) != 0 || s.st_size == 0)
-    return false;
+  if (::stat(base_name, &s) != 0)
+    {
+      gold_info(_("%s: stat: %s"), base_name, strerror(errno));
+      return false;
+    }
+  if (s.st_size == 0)
+    {
+      gold_info(_("%s: incremental base file is empty"), base_name);
+      return false;
+    }
+
+  // If we're using a base file, we want to open it read-only.
+  if (use_base_file)
+    writable = false;
 
-  int o = open_descriptor(-1, this->name_, O_RDWR, 0);
+  int oflags = writable ? O_RDWR : O_RDONLY;
+  int o = open_descriptor(-1, base_name, oflags, 0);
   if (o < 0)
-    gold_fatal(_("%s: open: %s"), this->name_, strerror(errno));
+    {
+      gold_info(_("%s: open: %s"), base_name, strerror(errno));
+      return false;
+    }
+
+  // If the base file and the output file are different, open a
+  // new output file and read the contents from the base file into
+  // the newly-mapped region.
+  if (use_base_file)
+    {
+      this->open(s.st_size);
+      ssize_t len = ::read(o, this->base_, s.st_size);
+      if (len < 0)
+        {
+         gold_info(_("%s: read failed: %s"), base_name, strerror(errno));
+         return false;
+        }
+      if (len < s.st_size)
+        {
+         gold_info(_("%s: file too short"), base_name);
+         return false;
+        }
+      ::close(o);
+      return true;
+    }
+
   this->o_ = o;
   this->file_size_ = s.st_size;
 
-  // If the file can't be mmapped, copying the content to an anonymous
-  // map will probably negate the performance benefits of incremental
-  // linking.  This could be helped by using views and loading only
-  // the necessary parts, but this is not supported as of now.
-  if (!this->map_no_anonymous())
+  if (!this->map_no_anonymous(writable))
     {
       release_descriptor(o, true);
       this->o_ = -1;
@@ -4688,7 +4734,7 @@ Output_file::resize(off_t file_size)
     {
       this->unmap();
       this->file_size_ = file_size;
-      if (!this->map_no_anonymous())
+      if (!this->map_no_anonymous(true))
        gold_fatal(_("%s: mmap: %s"), this->name_, strerror(errno));
     }
 }
@@ -4715,9 +4761,10 @@ Output_file::map_anonymous()
 }
 
 // Map the file into memory.  Return whether the mapping succeeded.
+// If WRITABLE is true, map with write access.
 
 bool
-Output_file::map_no_anonymous()
+Output_file::map_no_anonymous(bool writable)
 {
   const int o = this->o_;
 
@@ -4739,12 +4786,14 @@ Output_file::map_no_anonymous()
   // output file will wind up incomplete, but we will have already
   // exited.  The alternative to fallocate would be to use fdatasync,
   // but that would be a more significant performance hit.
-  if (::posix_fallocate(o, 0, this->file_size_) < 0)
+  if (writable && ::posix_fallocate(o, 0, this->file_size_) < 0)
     gold_fatal(_("%s: %s"), this->name_, strerror(errno));
 
   // Map the file into memory.
-  base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
-               MAP_SHARED, o, 0);
+  int prot = PROT_READ;
+  if (writable)
+    prot |= PROT_WRITE;
+  base = ::mmap(NULL, this->file_size_, prot, MAP_SHARED, o, 0);
 
   // The mmap call might fail because of file system issues: the file
   // system might not support mmap at all, or it might not support
@@ -4762,7 +4811,7 @@ Output_file::map_no_anonymous()
 void
 Output_file::map()
 {
-  if (this->map_no_anonymous())
+  if (this->map_no_anonymous(true))
     return;
 
   // The mmap call might fail because of file system issues: the file
index 8ca3598ab0cd98c6b94cfed51f66cee1d6888d66..da2e9cb735b04d9101264709b7023f3c32078b32 100644 (file)
@@ -4188,9 +4188,10 @@ class Output_file
 
   // Try to open an existing file. Returns false if the file doesn't
   // exist, has a size of 0 or can't be mmaped.  This method is
-  // thread-unsafe.
+  // thread-unsafe.  If BASE_NAME is not NULL, use the contents of
+  // that file as the base for incremental linking.
   bool
-  open_for_modification();
+  open_base_file(const char* base_name, bool writable);
 
   // Open the output file.  FILE_SIZE is the final size of the file.
   // If the file already exists, it is deleted/truncated.  This method
@@ -4275,7 +4276,7 @@ class Output_file
 
   // Map the file into memory.
   bool
-  map_no_anonymous();
+  map_no_anonymous(bool);
 
   // Unmap the file from memory (and flush to disk buffers).
   void
index 9eab85e820ff23d0c53b81a09ccd0f5a48695884..b0dc8640a9d98c56bef36a2b9452d074178f13e5 100644 (file)
@@ -1840,13 +1840,15 @@ incremental_test_3: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
        $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_1.o two_file_test_tmp.o two_file_test_2.o two_file_test_main.o
 
 check_PROGRAMS += incremental_test_4
+MOSTLYCLEANFILES += incremental_test_4.base
 incremental_test_4: two_file_test_1.o two_file_test_1b.o two_file_test_2_v1.o \
                    two_file_test_2.o two_file_test_main.o gcctestdir/ld
        cp -f two_file_test_2_v1.o two_file_test_tmp.o
        $(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp.o two_file_test_main.o
+       mv -f incremental_test_4 incremental_test_4.base
        @sleep 1
        cp -f two_file_test_2.o two_file_test_tmp.o
-       $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp.o two_file_test_main.o
+       $(CXXLINK) -Wl,--incremental-update,--incremental-base=incremental_test_4.base -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp.o two_file_test_main.o
 
 endif DEFAULT_TARGET_X86_64
 
index 2276095508e6f6526d7bf337e373573c97e6dc2b..8ab60685e603ec867b1efa8ce3fea51acb697288 100644 (file)
@@ -436,7 +436,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_35 = incremental_test_2 \
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     incremental_test_3 \
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     incremental_test_4
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_36 = two_file_test_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_36 = two_file_test_tmp.o \
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     incremental_test_4.base
 
 # These tests work with native and cross linkers.
 
@@ -4605,9 +4606,10 @@ uninstall-am:
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@                 two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     cp -f two_file_test_2_v1.o two_file_test_tmp.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     $(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     mv -f incremental_test_4 incremental_test_4.base
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     @sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     cp -f two_file_test_2.o two_file_test_tmp.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     $(CXXLINK) -Wl,--incremental-update,--incremental-base=incremental_test_4.base -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp.o two_file_test_main.o
 @NATIVE_OR_CROSS_LINKER_TRUE@script_test_10.o: script_test_10.s
 @NATIVE_OR_CROSS_LINKER_TRUE@  $(TEST_AS) -o $@ $<
 @NATIVE_OR_CROSS_LINKER_TRUE@script_test_10: $(srcdir)/script_test_10.t script_test_10.o gcctestdir/ld