// glib-memtrace.stp: Every 5 seconds, dump the memory usage of a single process as JSON
// Usage: stap -c gtk-demo ./glib-memtrace.stp

// g_malloc/g_slice globals
global g_malloced_total
global g_malloced_outstanding
// Note - you may need to increase these values
global g_heap[65536]
global g_slice_heap[65536]
global g_slice_total
global g_slice_outstanding

// GObject globals
global gobject_alive

// GLIB probes

probe glib.mem_alloc {
  if (target() == pid())
    {
      g_malloced_total += n_bytes
      g_malloced_outstanding += n_bytes
      g_heap[mem] = n_bytes
    }
}

probe glib.mem_realloc {
  if (target() == pid())
    {
      newbytes = n_bytes - g_heap[old_mem]
      delete g_heap[old_mem]
      if (newbytes > 0)
        g_malloced_total += newbytes
      g_malloced_outstanding += newbytes
      g_heap[mem] = n_bytes
    }
}

probe glib.mem_free {
  if (target() == pid())
    {
      g_malloced_outstanding -= g_heap[mem]
      delete g_heap[mem]
    }
}

probe glib.slice_alloc {
  if (target() == pid())
    {
      g_slice_total += n_bytes
      g_slice_outstanding += n_bytes
      g_slice_heap[mem] = n_bytes
    }
}

probe glib.slice_free {
  if (target() == pid())
    {
      g_slice_outstanding -= n_bytes
      delete g_slice_heap[mem]
    }
}

// GObject probes

probe gobject.object_new {
  if (target() == pid())
    {
      gobject_alive[type]++
    }
}
probe gobject.object_finalize {
  if (target() == pid())
    {
      if (gobject_alive[type] <= 1)
        delete gobject_alive[type]
      else
        gobject_alive[type]--
    }
}

probe begin {
  printf ("{ stats: [\n")
}

probe timer.sec(5) {
  printf (" {\n")
  printf ("  time: %d,\n", gettimeofday_ms())
  
  printf ("  gmalloc: {\n")
  printf ("  total: %d\n", g_malloced_total)
  printf ("  outstanding: %d", g_malloced_outstanding)
  printf ("  }\n")
  
  printf ("  gslice: {\n")
  printf ("  total: %d\n", g_slice_total)
  printf ("  outstanding: %d", g_slice_outstanding)
  printf ("  }\n")
  
  printf ("  gobject: {\n")
  foreach (a in gobject_alive) {
    printf ("%s: %d\n", a, gobject_alive[a])
  }
  printf ("  }\n")
  
  printf (" }\n")
}

probe end {
  printf ("] }\n")
}
