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 idunknown
push userunknown
push dateunknown
reviewerstglek
bugs686805
milestone13.0a1
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 */