HdrHistogram.NET icon indicating copy to clipboard operation
HdrHistogram.NET copied to clipboard

Examples

Open psantoro opened this issue 7 years ago • 2 comments

I've been using HdrHistogram for a while and have created some C# classes to simplify its usage. They allow me to enable of set of histograms via simple names in an application configuration file. The classes that use the enabled histograms can initialize and use them with only a small amount of code. I also have an F# version that uses F# modules/functions instead of classes. Here's a quick C# example:

// step 1 - initialize the histogram names that will be used in the current run from config file
List<string> names = cfg.getValues("histograms");

foreach (string name in names)
{
    Histograms.Add(name);
    _log.DebugFormat("enabled histogram: {0}", name);
}

// step 2 - initialize an enabled histogram within class it's used in

private static HistogramTimer _hgPostAck = null;
private static bool _hgPostAckEnabled = false;
public static readonly string HG_POSTACK = "postack";

_hgPostAckEnabled = Histograms.isEnabled(HG_POSTACK);

if (_hgPostAckEnabled)
    _hgPostAck = Histograms.makeHistogramTimer(HG_POSTACK, HistogramTimer.NSECS_IN_MIN * 10L, 3, false, 100); // 1 nsec to 10 min, 3 decimal point resolution, don't warmup, only log report every 100 calls

// step 3 - use histogram within class

try
{
    if (_hgPostAckEnabled)
        _hgPostAck.startTimer();

    // do work...
}
finally
{
    if (_hgPostAckEnabled)
    {
        _hgPostAck.recordTime();
        Histograms.logReport(HG_POSTACK, ScaleFactor.MSEC);
    }
}

Let me know if you are interested in these potential contributions. Note that my existing C# and F# code will most likely require some modifications before they can be included.

Peter Santoro

psantoro avatar Feb 02 '18 15:02 psantoro

Thanks @psantoro for your feedback. I can see that there could be some value in the enable/disable via config. However, I would rather keep HdrHistogram.NET agnostic of any config.

With this in mind, it seems that the key things here that you want are

  • Named histograms (via your factory method Histograms.makeHistogramTimer(HG_POSTACK, HistogramTimer.NSECS_IN_MIN * 10L, 3, false, 100);
  • Being able to record scope e.g. _hgPostAck.startTimer(); / _hgPostAck.recordTime();
  • only execute the recording/timing if enabled.

I think that each of these 3 features/requirements could be catered for.

We can extend HistogramFactory to allow the name to be specified e.g.

var recorder = HistogramFactory
                .With64BitBucketSize()                  //LongHistogram
                .WithValuesFrom(1)                      //Default value
                .WithValuesUpTo(TimeStamp.Minutes(10))  //Default value
                .WithPrecisionOf(3)                     //Default value
                .WithThreadSafeWrites()                 //Switches internal imp to concurrent version i.e. LongConcurrentHistogram
                .WithThreadSafeReads()                  //returns a Recorder that wraps the LongConcurrentHistogram
                .Named(HG_POSTACK)                      //New feature here
                .Create();

Recording of scope is already supported with the ext method RecordScope() i.e.

using(_hgPostAck.RecordScope())
{
    // do work...
}

We can also provide a Null Implementation so that if your config suggests that it should be disabled, then it just wont do anything.

public sealed class NullRecorder : IRecorder
{
    public static readonly IRecorder Instance = new NullRecorder();
    private NullRecorder()
    {    }

    public void RecordValue(long value)
    {    }

    public void RecordValueWithCount(long value, long count)
    {    }

    public void RecordValueWithExpectedInterval(long value, long expectedIntervalBetweenValueSamples)
    {    }
}

This could reduce your code to

// step 1 - initialize the histogram names that will be used in the current run from config file
List<string> names = cfg.getValues("histograms");

foreach (string name in names)
{
    Histograms.Add(name);
    _log.DebugFormat("enabled histogram: {0}", name);
}

// step 2 - initialize an enabled histogram within class it's used in

private static IRecorder _hgPostAck = null;
public static readonly string HG_POSTACK = "postack";

_hgPostAck = Histograms.isEnabled(HG_POSTACK)
    ? HistogramFactory
                .With64BitBucketSize()                  
                .WithValuesUpTo(TimeStamp.Minutes(10))
                .Named(HG_POSTACK)
                .Create()
    : NullRecorder.Instance;

// step 3 - use histogram within class
using(_hgPostAck.RecordScope())
{
    // do work...
}

I currently dont have any plans to support sampling e.g. "only record every 100 measurements". The goal of this library was to be so low cost with regards to call time, that this would be avoided. I would think that it would rather defeat the purpose of the tool? Maybe I am misunderstanding.

P.S. Sorry about the delay in my response, and thanks for using this Port of Gil's great tool.

LeeCampbell avatar Feb 13 '18 11:02 LeeCampbell

On 02/13/2018 06:58 AM, Lee Campbell wrote:

Thanks @psantoro https://github.com/psantoro for your feedback. I can see that there could be some value in the enable/disable via config. However, I would rather keep HdrHistogram.NET agnostic of any config.

With this in mind, it seems that the key things here that you want are

  • Named histograms (via your factory method |Histograms.makeHistogramTimer(HG_POSTACK, HistogramTimer.NSECS_IN_MIN * 10L, 3, false, 100);|
  • Being able to record scope e.g. |_hgPostAck.startTimer();| / |_hgPostAck.recordTime();|
  • only execute the recording/timing if enabled.

I think that each of these 3 features/requirements could be catered for.

We can extend |HistogramFactory| to allow the name to be specified e.g.

|var recorder = HistogramFactory .With64BitBucketSize() //LongHistogram .WithValuesFrom(1) //Default value .WithValuesUpTo(TimeStamp.Minutes(10)) //Default value .WithPrecisionOf(3) //Default value .WithThreadSafeWrites() //Switches internal imp to concurrent version i.e. LongConcurrentHistogram .WithThreadSafeReads() //returns a Recorder that wraps the LongConcurrentHistogram .Named(HG_POSTACK) //New feature here .Create(); |

Recording of scope is already supported with the ext method |RecordScope()| i.e.

|using(_hgPostAck.RecordScope()) { // do work... } |

We can also provide a Null Implementation so that if your config suggests that it should be disabled, then it just wont do anything.

|public sealed class NullRecorder : IRecorder { public static readonly IRecorder Instance = new NullRecorder(); private NullRecorder() { } public void RecordValue(long value) { } public void RecordValueWithCount(long value, long count) { } public void RecordValueWithExpectedInterval(long value, long expectedIntervalBetweenValueSamples) { } } |

This could reduce your code to

|// step 1 - initialize the histogram names that will be used in the current run from config file List names = cfg.getValues("histograms"); foreach (string name in names) { Histograms.Add(name); _log.DebugFormat("enabled histogram: {0}", name); } // step 2 - initialize an enabled histogram within class it's used in private static IRecorder _hgPostAck = null; public static readonly string HG_POSTACK = "postack"; _hgPostAck = Histograms.isEnabled(HG_POSTACK) ? HistogramFactory .With64BitBucketSize() .WithValuesUpTo(TimeStamp.Minutes(10)) .Named(HG_POSTACK) .Create() : NullRecorder.Instance; // step 3 - use histogram within class using(_hgPostAck.RecordScope()) { // do work... } |

I currently dont have any plans to support /sampling/ e.g. "only record every 100 measurements". The goal of this library was to be so low cost with regards to call time, that this would be avoided. I would think that it would rather defeat the purpose of the tool? Maybe I am misunderstanding.

P.S. Sorry about the delay in my response, and thanks for using this Port of Gil's great tool.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/HdrHistogram/HdrHistogram.NET/issues/63#issuecomment-365246191, or mute the thread https://github.com/notifications/unsubscribe-auth/ABnBRhSrtK9zgzw_EcZ93BDCYW9J0u93ks5tUXjvgaJpZM4R3Xc_.

Lee,

Thank you for your response. BTW, my code doesn't do sampling. The last parameter to my |Histograms.makeHistogramTimer API (e.g. 100 above) is used to limit how often the enabled histograms are logged. The system that I initially used |HdrHistogram.NET on (back in 2016) runs 24/7 and I needed a way to get performance information periodically without shutting down the system. The time between histogram measurements varied greatly (minutes to days, depending on demand).

I wasn't aware of |HistogramFactory, |||RecordScope, or|||IRecorder; therefore, I do agree with your ideas on how to better handle named histograms and enabled/disabled histograms. I guess I missed those samples when I started using ||HdrHistogram.NET in 2016.

||I've watched a few of Gil's videos and was very glad to find this port of his |||HdrHistogram tool.| ||| Thank you for maintaining ||HdrHistogram.NET,|

Peter Santoro |||

psantoro avatar Feb 15 '18 02:02 psantoro