15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using System;
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using System.Collections;
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using System.Collections.Generic;
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using System.Diagnostics;
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using System.Runtime.InteropServices;
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using System.Text;
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace StatsViewer
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// <summary>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// The stats table shared memory segment contains this
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// header structure.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// </summary>
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [StructLayout(LayoutKind.Sequential)]
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  internal struct StatsFileHeader {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int version;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int size;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int max_counters;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int max_threads;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// <summary>
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// An entry in the StatsTable.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// </summary>
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class StatsTableEntry {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public StatsTableEntry(int id, string name, StatsTable table) {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id_ = id;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name_ = name;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      table_ = table;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// The unique id for this entry
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int id { get { return id_; } }
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// The name for this entry.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public string name { get { return name_; } }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// The value of this entry now.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int GetValue(int filter_pid) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return table_.GetValue(id_, filter_pid);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private int id_;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private string name_;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private StatsTable table_;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An interface for StatsCounters
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  interface IStatsCounter {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The name of the counter
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string name { get; }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A counter.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class StatsCounter : IStatsCounter {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public StatsCounter(StatsTableEntry entry) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entry_ = entry;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public string name {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return entry_.name;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int GetValue(int filter_pid) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return entry_.GetValue(filter_pid);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private StatsTableEntry entry_;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A timer.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class StatsTimer : IStatsCounter {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public StatsTimer(StatsTableEntry entry)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entry_ = entry;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public string name {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return entry_.name;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int GetValue(int filter_pid) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return entry_.GetValue(filter_pid);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private StatsTableEntry entry_;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A rate.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class StatsCounterRate : IStatsCounter
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public StatsCounterRate(StatsCounter counter, StatsTimer timer) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      counter_ = counter;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timer_ = timer;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public string name { get { return counter_.name; } }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int GetCount(int filter_pid) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return counter_.GetValue(filter_pid);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int GetTime(int filter_pid) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return timer_.GetValue(filter_pid);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private StatsCounter counter_;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private StatsTimer timer_;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// <summary>
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// This is a C# reader for the chrome stats_table.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// </summary>
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class StatsTable {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internal const int kMaxThreadNameLength = 32;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internal const int kMaxCounterNameLength = 32;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Open a StatsTable
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public StatsTable() {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region Public Properties
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Get access to the counters in the table.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public StatsTableCounters Counters() {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return new StatsTableCounters(this);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Get access to the processes in the table
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public ICollection Processes {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return new StatsTableProcesses(this);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region Internal Properties
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The internal methods are accessible to the enumerators
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and helper classes below.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Access to the table header
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internal StatsFileHeader Header {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get { return header_; }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Get the offset of the ThreadName table
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internal long ThreadNamesOffset {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return memory_.ToInt64() + Marshal.SizeOf(typeof(StatsFileHeader));
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Get the offset of the PIDs table
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internal long PidsOffset {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        long offset = ThreadNamesOffset;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Thread names table
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        offset += AlignedSize(header_.max_threads * kMaxThreadNameLength * 2);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Thread TID table
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        offset += AlignedSize(header_.max_threads *
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Marshal.SizeOf(typeof(int)));
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return offset;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Get the offset of the CounterName table
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internal long CounterNamesOffset {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        long offset = PidsOffset;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Thread PID table
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        offset += AlignedSize(header_.max_threads *
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Marshal.SizeOf(typeof(int)));
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return offset;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Get the offset of the Data table
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internal long DataOffset {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        long offset = CounterNamesOffset;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Counter names table
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        offset += AlignedSize(header_.max_counters *
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kMaxCounterNameLength * 2);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return offset;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region Public Methods
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Opens the memory map
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <returns></returns>
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <param name="name">The name of the file to open</param>
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public bool Open(string name) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      map_handle_ =
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Win32.OpenFileMapping((int)Win32.MapAccess.FILE_MAP_WRITE, false,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              name);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (map_handle_ == IntPtr.Zero)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memory_ =
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Win32.MapViewOfFile(map_handle_, (int)Win32.MapAccess.FILE_MAP_WRITE,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            0,0, 0);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (memory_ == IntPtr.Zero) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Win32.CloseHandle(map_handle_);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      header_ = (StatsFileHeader)Marshal.PtrToStructure(memory_, header_.GetType());
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Close the mapped file.
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public void Close() {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Win32.UnmapViewOfFile(memory_);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Win32.CloseHandle(map_handle_);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Zero out the stats file.
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public void Zero() {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      long offset = DataOffset;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int threads = 0; threads < header_.max_threads; threads++) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (int counters = 0; counters < header_.max_counters; counters++) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Marshal.WriteInt32((IntPtr) offset, 0);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          offset += Marshal.SizeOf(typeof(int));
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Get the value for a StatsCounterEntry now.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <returns></returns>
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <param name="filter_pid">If a specific PID is being queried, filter to this PID.  0 means use all data.</param>
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <param name="id">The id of the CounterEntry to get the value for.</param>
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int GetValue(int id, int filter_pid) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      long pid_offset = PidsOffset;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      long data_offset = DataOffset;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data_offset += id * (Header.max_threads *
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Marshal.SizeOf(typeof(int)));
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int rv = 0;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int cols = 0; cols < Header.max_threads; cols++)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int pid = Marshal.ReadInt32((IntPtr)pid_offset);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (filter_pid == 0 || filter_pid == pid)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          rv += Marshal.ReadInt32((IntPtr)data_offset);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        data_offset += Marshal.SizeOf(typeof(int));
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pid_offset += Marshal.SizeOf(typeof(int));
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return rv;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region Private Methods
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Align to 4-byte boundaries
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <param name="size"></param>
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <returns></returns>
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private long AlignedSize(long size) {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Debug.Assert(sizeof(int) == 4);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return size + (sizeof(int) - (size % sizeof(int))) % sizeof(int);
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region Private Members
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private IntPtr memory_;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private IntPtr map_handle_;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private StatsFileHeader header_;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// <summary>
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// Enumerable list of Counters in the StatsTable
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// </summary>
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class StatsTableCounters : ICollection {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Create the list of counters
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <param name="table"></param>
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// pid</param>
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public StatsTableCounters(StatsTable table) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      table_ = table;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      counter_hi_water_mark_ = -1;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      counters_ = new List<IStatsCounter>();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FindCounters();
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Scans the table for new entries.
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public void Update() {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FindCounters();
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region IEnumerable Members
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public IEnumerator GetEnumerator() {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return counters_.GetEnumerator();
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region ICollection Members
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public void CopyTo(Array array, int index) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      throw new Exception("The method or operation is not implemented.");
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int Count {
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return counters_.Count;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public bool IsSynchronized {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        throw new Exception("The method or operation is not implemented.");
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public object SyncRoot {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        throw new Exception("The method or operation is not implemented.");
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region Private Methods
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Create a counter based on an entry
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <param name="id"></param>
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <param name="name"></param>
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <returns></returns>
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private IStatsCounter NameToCounter(int id, string name)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IStatsCounter rv = null;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // check if the name has a type encoded
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (name.Length > 2 && name[1] == ':')
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        StatsTableEntry entry = new StatsTableEntry(id, name.Substring(2), table_);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        switch (name[0])
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          case 't':
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            rv = new StatsTimer(entry);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            break;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          case 'c':
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            rv = new StatsCounter(entry);
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            break;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        StatsTableEntry entry = new StatsTableEntry(id, name, table_);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rv = new StatsCounter(entry);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return rv;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we have two StatsTableEntries with the same name,
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // attempt to upgrade them to a higher level type.
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Example:  A counter + a timer == a rate!
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private void UpgradeCounter(IStatsCounter old_counter, IStatsCounter counter)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (old_counter is StatsCounter && counter is StatsTimer)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        StatsCounterRate rate = new StatsCounterRate(old_counter as StatsCounter,
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          counter as StatsTimer);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        counters_.Remove(old_counter);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        counters_.Add(rate);
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else if (old_counter is StatsTimer && counter is StatsCounter)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        StatsCounterRate rate = new StatsCounterRate(counter as StatsCounter,
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         old_counter as StatsTimer);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        counters_.Remove(old_counter);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        counters_.Add(rate);
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Find the counters in the table and insert into the counters_
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// hash table.
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private void FindCounters()
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Debug.Assert(table_.Header.max_counters > 0);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int index = counter_hi_water_mark_;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      do
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Find an entry in the table.
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        index++;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        long offset = table_.CounterNamesOffset +
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (index * StatsTable.kMaxCounterNameLength * 2);
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        string name = Marshal.PtrToStringUni((IntPtr)offset);
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (name.Length == 0)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Record that we've already looked at this StatsTableEntry.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        counter_hi_water_mark_ = index;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IStatsCounter counter = NameToCounter(index, name);
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (counter != null)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          IStatsCounter old_counter = FindExistingCounter(counter.name);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (old_counter != null)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            UpgradeCounter(old_counter, counter);
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          else
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            counters_.Add(counter);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } while (index < table_.Header.max_counters - 1);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Find an existing counter in our table
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <param name="name"></param>
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private IStatsCounter FindExistingCounter(string name) {
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      foreach (IStatsCounter ctr in counters_)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (ctr.name == name)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return ctr;
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return null;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region Private Members
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private StatsTable table_;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private List<IStatsCounter> counters_;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Highest index of counters processed.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private int counter_hi_water_mark_;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// <summary>
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// A collection of processes
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /// </summary>
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class StatsTableProcesses : ICollection
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Constructor
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <param name="table"></param>
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public StatsTableProcesses(StatsTable table) {
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      table_ = table;
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pids_ = new List<int>();
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Initialize();
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region ICollection Members
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public void CopyTo(Array array, int index) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      throw new Exception("The method or operation is not implemented.");
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int Count {
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return pids_.Count;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public bool IsSynchronized {
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        throw new Exception("The method or operation is not implemented.");
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public object SyncRoot {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get {
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        throw new Exception("The method or operation is not implemented.");
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region IEnumerable Members
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public IEnumerator GetEnumerator() {
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return pids_.GetEnumerator();
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// <summary>
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// Initialize the pid list.
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /// </summary>
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private void Initialize() {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      long offset = table_.ThreadNamesOffset;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int index = 0; index < table_.Header.max_threads; index++) {
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        string thread_name = Marshal.PtrToStringUni((IntPtr)offset);
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (thread_name.Length > 0) {
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          long pidOffset = table_.PidsOffset + index *
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            Marshal.SizeOf(typeof(int));
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          int pid = Marshal.ReadInt32((IntPtr)pidOffset);
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!pids_.Contains(pid))
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            pids_.Add(pid);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        offset += StatsTable.kMaxThreadNameLength * 2;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #region Private Members
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private StatsTable table_;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private List<int> pids_;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endregion
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
547