/* -*- js-indent-level: 4; indent-tabs-mode: nil -*- */
/* vim:set ts=4 sw=4 sts=4 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var MemoryStats = {};

/**
 * Statistics that we want to retrieve and display after every test is
 * done.  The keys of this table are intended to be identical to the
 * relevant attributes of nsIMemoryReporterManager.  However, since
 * nsIMemoryReporterManager doesn't necessarily support all these
 * statistics in all build configurations, we also use this table to
 * tell us whether statistics are supported or not.
 */
var MEM_STAT_UNKNOWN = 0;
var MEM_STAT_UNSUPPORTED = 1;
var MEM_STAT_SUPPORTED = 2;

MemoryStats._hasMemoryStatistics = {};
MemoryStats._hasMemoryStatistics.vsize = MEM_STAT_UNKNOWN;
MemoryStats._hasMemoryStatistics.vsizeMaxContiguous = MEM_STAT_UNKNOWN;
MemoryStats._hasMemoryStatistics.residentFast = MEM_STAT_UNKNOWN;
MemoryStats._hasMemoryStatistics.heapAllocated = MEM_STAT_UNKNOWN;

MemoryStats._getService = function (className, interfaceName) {
  var service;
  try {
    service = Cc[className].getService(Ci[interfaceName]);
  } catch (e) {
    service = SpecialPowers.Cc[className].getService(
      SpecialPowers.Ci[interfaceName]
    );
  }
  return service;
};

MemoryStats._nsIFile = function (pathname) {
  var f;
  var contractID = "@mozilla.org/file/local;1";
  try {
    f = Cc[contractID].createInstance(Ci.nsIFile);
  } catch (e) {
    f = SpecialPowers.Cc[contractID].createInstance(SpecialPowers.Ci.nsIFile);
  }
  f.initWithPath(pathname);
  return f;
};

MemoryStats.constructPathname = function (directory, basename) {
  var d = MemoryStats._nsIFile(directory);
  d.append(basename);
  return d.path;
};

MemoryStats.dump = function (
  testNumber,
  testURL,
  dumpOutputDirectory,
  dumpAboutMemory,
  dumpDMD
) {
  // Use dump because treeherder uses --quiet, which drops 'info'
  // from the structured logger.
  var info = function (message) {
    dump(message + "\n");
  };

  var mrm = MemoryStats._getService(
    "@mozilla.org/memory-reporter-manager;1",
    "nsIMemoryReporterManager"
  );
  var statMessage = "";
  for (var stat in MemoryStats._hasMemoryStatistics) {
    var supported = MemoryStats._hasMemoryStatistics[stat];
    var firstAccess = false;
    if (supported == MEM_STAT_UNKNOWN) {
      firstAccess = true;
      try {
        void mrm[stat];
        supported = MEM_STAT_SUPPORTED;
      } catch (e) {
        supported = MEM_STAT_UNSUPPORTED;
      }
      MemoryStats._hasMemoryStatistics[stat] = supported;
    }
    if (supported == MEM_STAT_SUPPORTED) {
      var sizeInMB = Math.round(mrm[stat] / (1024 * 1024));
      statMessage += " | " + stat + " " + sizeInMB + "MB";
    } else if (firstAccess) {
      info(
        "MEMORY STAT " + stat + " not supported in this build configuration."
      );
    }
  }
  if (statMessage.length) {
    info("MEMORY STAT" + statMessage);
  }

  if (dumpAboutMemory) {
    var basename = "about-memory-" + testNumber + ".json.gz";
    var dumpfile = MemoryStats.constructPathname(dumpOutputDirectory, basename);
    info(testURL + " | MEMDUMP-START " + dumpfile);
    let md = MemoryStats._getService(
      "@mozilla.org/memory-info-dumper;1",
      "nsIMemoryInfoDumper"
    );
    md.dumpMemoryReportsToNamedFile(
      dumpfile,
      function () {
        info("TEST-INFO | " + testURL + " | MEMDUMP-END");
      },
      null,
      /* anonymize = */ false,
      /* minimize memory usage = */ false
    );
  }

  if (dumpDMD) {
    let md = MemoryStats._getService(
      "@mozilla.org/memory-info-dumper;1",
      "nsIMemoryInfoDumper"
    );
    md.dumpMemoryInfoToTempDir(
      String(testNumber),
      /* anonymize = */ false,
      /* minimize memory usage = */ false
    );
  }
};
