/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; ChromeUtils.import("resource://gre/modules/GCTelemetry.jsm", this); function do_register_cleanup() { GCTelemetry.shutdown(); } /* * These tests are very basic, my goal was to add enough testing to support * a change made in Bug 1424760. TODO Bug 1429635 for adding more extensive * tests and deleting this comment. */ function run_test() { // The limit on the number of fields in a GCMajor object. const limit = 24; // The number of fields that the make_gc() test function generates. const make_gc_fields = 19; // Test initialisation Assert.ok(GCTelemetry.init(), "Initialize success"); Assert.ok(!GCTelemetry.init(), "Wont initialize twice"); // Test the basic success path. // There are currently no entries assert_num_entries(0, false); // Add an entry GCTelemetry.observeRaw(make_gc()); // Get it back. assert_num_entries(1, false); Assert.equal(make_gc_fields, Object.keys(get_entry()).length); // "true" will cause the entry to be clared. assert_num_entries(1, true); // There are currently no entries. assert_num_entries(0, false); // Test too many fields let my_big_gc = make_gc(); for (let i = 0; i < 100; i++) { my_big_gc["new_property_" + i] = "Data"; } GCTelemetry.observeRaw(my_big_gc); // Assert that it was recorded but has only 7 fields. Assert.equal(7, Object.keys(get_entry()).length); assert_num_entries(1, true); assert_num_entries(0, false); let my_gc_exact = make_gc(); Assert.equal(make_gc_fields, Object.keys(my_gc_exact).length); for (let i = 0; i < limit - make_gc_fields; i++) { my_gc_exact["new_property_" + i] = "Data"; } GCTelemetry.observeRaw(my_gc_exact); // Assert that it was recorded has all the fields. Assert.equal(limit, Object.keys(get_entry()).length); assert_num_entries(1, true); assert_num_entries(0, false); // Exactly too many fields. let my_gc_too_many = make_gc(); for (let i = 0; i < limit - make_gc_fields + 1; i++) { my_gc_too_many["new_property_" + i] = "Data"; } GCTelemetry.observeRaw(my_gc_too_many); // Assert that it was recorded but has only 7 fields. Assert.equal(7, Object.keys(get_entry()).length); assert_num_entries(1, true); assert_num_entries(0, false); } function assert_num_entries(expect, clear) { let entries = GCTelemetry.entries("main", clear); Assert.equal(expect, entries.worst.length, expect + " worst entries"); // Randomly sampled GCs are only recorded for content processes Assert.equal(0, entries.random.length, expect + " random entries"); } function get_entry() { let entries = GCTelemetry.entries("main", false); Assert.ok(entries, "Got entries object"); Assert.ok(entries.random, "Has random property"); Assert.ok(entries.worst, "Has worst property"); let entry = entries.worst[0]; Assert.ok(entry, "Got worst entry"); return entry; } /* * These events are not exactly well-formed, but good enough. For example * there's no guantee that all the pause times add up to total time, or * that max_pause is correct. */ function make_gc() { // Timestamps are in milliseconds since startup. All the times here // are wall-clock times, which may not be monotonically increasing. let timestamp = Math.random() * 1000000; let gc = { "status": "completed", "timestamp": timestamp, // All durations are in milliseconds. "max_pause": Math.random() * 95 + 5, "total_time": Math.random() * 500 + 500, // Sum of all slice times. "zones_collected": 9, "total_zones": 9, "total_compartments": 309, "minor_gcs": 44, "store_buffer_overflows": 19, "mmu_20ms": 0, "mmu_50ms": 0, "nonincremental_reason": "GCBytesTrigger", "allocated_bytes": 38853696, // in bytes "added_chunks": 54, "removed_chunks": 12, "slices": 15, "slice_number": 218, // The first slice number for this GC event. "slices_list": [ { "slice": 218, // The global index of this slice. "pause": Math.random() * 2 + 28, "reason": "SET_NEW_DOCUMENT", "initial_state": "NotActive", "final_state": "Mark", "budget": "10ms", "page_faults": 1, "start_timestamp": timestamp + Math.random() * 50000, "times": { "wait_background_thread": 0.012, "mark_discard_code": 2.845, "purge": 0.723, "mark": 9.831, "mark_roots": 0.102, "buffer_gray_roots": 3.095, "mark_cross_compartment_wrappers": 0.039, "mark_c_and_js_stacks": 0.005, "mark_runtime_wide_data": 2.313, "mark_embedding": 0.117, "mark_compartments": 2.27, "unmark": 1.063, "minor_gcs_to_evict_nursery": 8.701, }, }, ], "totals": { "wait_background_thread": 0.012, "mark_discard_code": 2.845, "purge": 0.723, "mark": 9.831, "mark_roots": 0.102, "buffer_gray_roots": 3.095, "mark_cross_compartment_wrappers": 0.039, "mark_c_and_js_stacks": 0.005, "mark_runtime_wide_data": 2.313, "mark_embedding": 0.117, "mark_compartments": 2.27, "unmark": 1.063, "minor_gcs_to_evict_nursery": 8.701, }, }; return gc; }