Bug 686805 part 6 - Add functions to display stats about seekable compressed streams. r=tglek
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 22 Feb 2012 08:12:15 +0100
changeset 90260 240113669206870d57913ce3cef8126a677997f4
parent 90259 43927df96c25afd954a61dca4466e06292039cea
child 90261 fb7252059ce5c3d38c1c6ebda880463fc48a8007
push id783
push userlsblakk@mozilla.com
push dateTue, 24 Apr 2012 17:33:42 +0000
treeherdermozilla-beta@11faed19f136 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstglek
bugs686805
milestone13.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 686805 part 6 - Add functions to display stats about seekable compressed streams. r=tglek
mozglue/linker/CustomElf.cpp
mozglue/linker/CustomElf.h
mozglue/linker/ElfLoader.cpp
mozglue/linker/ElfLoader.h
mozglue/linker/Mappable.cpp
mozglue/linker/Mappable.h
--- a/mozglue/linker/CustomElf.cpp
+++ b/mozglue/linker/CustomElf.cpp
@@ -213,16 +213,17 @@ CustomElf::Load(Mappable *mappable, cons
   elf->l_addr = elf->base;
   elf->l_name = elf->GetPath();
   elf->l_ld = elf->GetPtr<Dyn>(dyn->p_vaddr);
   ElfLoader::Singleton.Register(elf);
 
   if (!elf->InitDyn(dyn))
     return NULL;
 
+  elf->stats("oneLibLoaded");
   debug("CustomElf::Load(\"%s\", %x) = %p", path, flags,
         static_cast<void *>(elf));
   return elf;
 }
 
 CustomElf::~CustomElf()
 {
   debug("CustomElf::~CustomElf(%p [\"%s\"])",
@@ -298,16 +299,18 @@ CustomElf::GetSymbolPtrInDeps(const char
 #else
     if (strcmp(symbol + 2, "cxa_atexit") == 0)
       return FunctionPtr(&ElfLoader::__wrap_cxa_atexit);
 #endif
     if (strcmp(symbol + 2, "cxa_finalize") == 0)
       return FunctionPtr(&ElfLoader::__wrap_cxa_finalize);
     if (strcmp(symbol + 2, "dso_handle") == 0)
       return const_cast<CustomElf *>(this);
+    if (strcmp(symbol + 2, "moz_linker_stats") == 0)
+      return FunctionPtr(&ElfLoader::stats);
   } else if (symbol[0] == 's' && symbol[1] == 'i') {
     if (strcmp(symbol + 2, "gnal") == 0)
       return FunctionPtr(__wrap_signal);
     if (strcmp(symbol + 2, "gaction") == 0)
       return FunctionPtr(__wrap_sigaction);
   }
 
   void *sym;
@@ -365,16 +368,22 @@ CustomElf::GetSymbol(const char *symbol,
 }
 
 bool
 CustomElf::Contains(void *addr) const
 {
   return base.Contains(addr);
 }
 
+void
+CustomElf::stats(const char *when) const
+{
+  mappable->stats(when, GetPath());
+}
+
 bool
 CustomElf::LoadSegment(const Phdr *pt_load) const
 {
   if (pt_load->p_type != PT_LOAD) {
     debug("%s: Elf::LoadSegment only takes PT_LOAD program headers", GetPath());
     return false;;
   }
 
--- a/mozglue/linker/CustomElf.h
+++ b/mozglue/linker/CustomElf.h
@@ -227,16 +227,23 @@ public:
 
   /**
    * Inherited from LibHandle
    */
   virtual ~CustomElf();
   virtual void *GetSymbolPtr(const char *symbol) const;
   virtual bool Contains(void *addr) const;
 
+  /**
+   * Shows some stats about the Mappable instance. The when argument is to be
+   * used by the caller to give an identifier of the when the stats call is
+   * made.
+   */
+  void stats(const char *when) const;
+
 private:
   /**
    * Returns a pointer to the Elf Symbol in the Dynamic Symbol table
    * corresponding to the given symbol name (with a pre-computed hash).
    */
   const Elf::Sym *GetSymbol(const char *symbol, unsigned long hash) const;
 
   /**
--- a/mozglue/linker/ElfLoader.cpp
+++ b/mozglue/linker/ElfLoader.cpp
@@ -340,16 +340,25 @@ ElfLoader::~ElfLoader()
         /* Not removing, since it could have references to other libraries,
          * destroying them as a side effect, and possibly leaving dangling
          * pointers in the handle list we're scanning */
       }
     }
   }
 }
 
+void
+ElfLoader::stats(const char *when)
+{
+  for (LibHandleList::iterator it = Singleton.handles.begin();
+       it < Singleton.handles.end(); ++it)
+    if (!(*it)->IsSystemElf())
+      static_cast<CustomElf *>(*it)->stats(when);
+}
+
 #ifdef __ARM_EABI__
 int
 ElfLoader::__wrap_aeabi_atexit(void *that, ElfLoader::Destructor destructor,
                                void *dso_handle)
 {
   Singleton.destructors.push_back(
     DestructorCaller(destructor, that, dso_handle));
   return 0;
--- a/mozglue/linker/ElfLoader.h
+++ b/mozglue/linker/ElfLoader.h
@@ -279,16 +279,23 @@ private:
   ~ElfLoader();
 
   /* Bookkeeping */
   typedef std::vector<LibHandle *> LibHandleList;
   LibHandleList handles;
 
 protected:
   friend class CustomElf;
+  /**
+   * Show some stats about Mappables in CustomElfs. The when argument is to
+   * be used by the caller to give an identifier of the when the stats call
+   * is made.
+   */
+  static void stats(const char *when);
+
   /* Definition of static destructors as to be used for C++ ABI compatibility */
   typedef void (*Destructor)(void *object);
 
   /**
    * C++ ABI makes static initializers register destructors through a specific
    * atexit interface. On glibc/linux systems, the dso_handle is a pointer
    * within a given library. On bionic/android systems, it is an undefined
    * symbol. Making sense of the value is not really important, and all that
--- a/mozglue/linker/Mappable.cpp
+++ b/mozglue/linker/Mappable.cpp
@@ -345,17 +345,17 @@ MappableSeekableZStream::Create(const ch
 
   mappable->chunkAvail = new unsigned char[mappable->zStream.GetChunksNum()];
   memset(mappable->chunkAvail, 0, mappable->zStream.GetChunksNum());
 
   return mappable.forget();
 }
 
 MappableSeekableZStream::MappableSeekableZStream(Zip *zip)
-: zip(zip) { }
+: zip(zip), chunkAvailNum(0) { }
 
 MappableSeekableZStream::~MappableSeekableZStream()
 {
   pthread_mutex_destroy(&mutex);
 }
 
 void *
 MappableSeekableZStream::mmap(const void *addr, size_t length, int prot,
@@ -468,16 +468,20 @@ MappableSeekableZStream::ensure(const vo
     if (map->prot & PROT_EXEC) {
       /* We just extracted data that may be executed in the future.
        * We thus need to ensure Instruction and Data cache coherency. */
       debug("cacheflush(%p, %p)", *buffer + chunkStart, *buffer + (chunkStart + length));
       cacheflush(reinterpret_cast<uintptr_t>(*buffer + chunkStart),
                  reinterpret_cast<uintptr_t>(*buffer + (chunkStart + length)), 0);
     }
 #endif
+    /* Only count if we haven't already decompressed parts of the chunk */
+    if (chunkAvail[chunk] == 0)
+      chunkAvailNum++;
+
     chunkAvail[chunk] = (length + PAGE_SIZE - 1) / PAGE_SIZE;
   }
 
   /* Flip the chunk mapping protection to the recorded flags. We could
    * also flip the protection for other mappings of the same chunk,
    * but it's easier to skip that and let further segfaults call
    * ensure again. */
   const void *chunkAddr = reinterpret_cast<const void *>
@@ -493,8 +497,30 @@ MappableSeekableZStream::ensure(const vo
 
   debug("mprotect @%p, 0x%x, 0x%x", start, length, map->prot);
   if (mprotect(const_cast<void *>(start), length, map->prot) == 0)
     return true;
 
   log("mprotect failed");
   return false;
 }
+
+void
+MappableSeekableZStream::stats(const char *when, const char *name) const
+{
+  size_t nEntries = zStream.GetChunksNum();
+  debug("%s: %s; %ld/%ld chunks decompressed",
+        name, when, chunkAvailNum, nEntries);
+
+  size_t len = 64;
+  AutoDeleteArray<char> map = new char[len + 3];
+  map[0] = '[';
+
+  for (size_t i = 0, j = 1; i < nEntries; i++, j++) {
+    map[j] = chunkAvail[i] ? '*' : '_';
+    if ((j == len) || (i == nEntries - 1)) {
+      map[j + 1] = ']';
+      map[j + 2] = '\0';
+      debug("%s", static_cast<char *>(map));
+      j = 0;
+    }
+  }
+}
--- a/mozglue/linker/Mappable.h
+++ b/mozglue/linker/Mappable.h
@@ -44,16 +44,26 @@ public:
    * available.
    */
   virtual bool ensure(const void *addr) { return true; }
 
   /**
    * Indicate to a Mappable instance that no further mmap is going to happen.
    */
   virtual void finalize() = 0;
+
+  /**
+   * Shows some stats about the Mappable instance.
+   * Meant for MappableSeekableZStream only.
+   * As Mappables don't keep track of what they are instanciated for, the name
+   * argument is used to make the stats logging useful to the reader. The when
+   * argument is to be used by the caller to give an identifier of the when
+   * the stats call is made.
+   */
+  virtual void stats(const char *when, const char *name) const { }
 };
 
 /**
  * Mappable implementation for plain files
  */
 class MappableFile: public Mappable
 {
 public:
@@ -175,16 +185,17 @@ public:
   static MappableSeekableZStream *Create(const char *name, Zip *zip,
                                          Zip::Stream *stream);
 
   /* Inherited from Mappable */
   virtual void *mmap(const void *addr, size_t length, int prot, int flags, off_t offset);
   virtual void munmap(void *addr, size_t length);
   virtual void finalize();
   virtual bool ensure(const void *addr);
+  virtual void stats(const char *when, const char *name) const;
 
 private:
   MappableSeekableZStream(Zip *zip);
 
   /* Zip reference */
   mozilla::RefPtr<Zip> zip;
 
   /* Decompression buffer */
@@ -228,13 +239,16 @@ private:
 
   /* List of all mappings */
   std::vector<LazyMap> lazyMaps;
 
   /* Array keeping track of which chunks have already been decompressed.
    * Each value is the number of pages decompressed for the given chunk. */
   AutoDeleteArray<unsigned char> chunkAvail;
 
+  /* Number of chunks that have already been decompressed. */
+  size_t chunkAvailNum;
+
   /* Mutex protecting decompression */
   pthread_mutex_t mutex;
 };
 
 #endif /* Mappable_h */