// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// You should run this with v8, like v8_shell alloc.js datafile.json

function toHex(num) {
  var str = "";
  var table = "0123456789abcdef";
  while (num != 0) {
    str = table.charAt(num & 0xf) + str;
    num >>= 4;
  }
  return str;
}

function parseEvents(z) {
  var crits =  { }
  var calls = { }

  for (var i = 0, il = z.length; i < il; ++i) {
    var e = z[i];

    if (e['eventtype'] == 'EVENT_TYPE_ENTER_CS' ||
        e['eventtype'] == 'EVENT_TYPE_TRYENTER_CS' ||
        e['eventtype'] == 'EVENT_TYPE_LEAVE_CS') {
      cs = e['critical_section'];
      if (!(cs in crits)) {
        crits[cs] = [ ];
      }
      crits[cs].push(e);
    }
  }

  // Verify that the locks get unlocked, and operations stay on the same thread.
  for (var key in crits) {
    var cs = key;
    var es = crits[key];

    var tid_stack = [ ];
    for (var j = 0, jl = es.length; j < jl; ++j) {
      var e = es[j];
      if (e['eventtype'] == 'EVENT_TYPE_ENTER_CS') {
        tid_stack.push(e);
      } else if (e['eventtype'] == 'EVENT_TYPE_TRYENTER_CS') {
        if (e['retval'] != 0)
          tid_stack.push(e);
      } else if (e['eventtype'] == 'EVENT_TYPE_LEAVE_CS') {
        if (tid_stack.length == 0) {
          print('fail ' + e);
        }
        var tid = tid_stack.pop()
        if (tid['thread'] != e['thread']) {
          print('fail ' + tid);
        }
      }
    }
  }

  // Look for long-held / contended locks.  We can't really know it is
  // contended without looking if anyone is waiting on the embedded event...
  // Just look for locks are are held a long time?  Not so good...
  for (var key in crits) {
    var cs = key;
    var es = crits[key];

    var tid_stack = [ ];
    for (var j = 0, jl = es.length; j < jl; ++j) {
      var e = es[j];
      if (e['eventtype'] == 'EVENT_TYPE_ENTER_CS') {
        tid_stack.push(e);
      } else if (e['eventtype'] == 'EVENT_TYPE_TRYENTER_CS') {
        if (e['retval'] != 0)
          tid_stack.push(e);
      } else if (e['eventtype'] == 'EVENT_TYPE_LEAVE_CS') {
        if (tid_stack.length == 0) {
          print('fail ' + e);
        }
        var tid = tid_stack.pop();
        var dur = e['ms'] - tid['ms'];
        if (dur > 0.1) {
          print('Lock: 0x' + toHex(cs) + ' for ' + dur + ' at: ' + e['ms']);
        }
      }
    }
  }
}
