Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Examples #63

Open
psantoro opened this issue Feb 2, 2018 · 2 comments
Open

Examples #63

psantoro opened this issue Feb 2, 2018 · 2 comments

Comments

@psantoro
Copy link

psantoro commented Feb 2, 2018

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

@LeeCampbell
Copy link
Collaborator

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.

@psantoro
Copy link
Author

psantoro commented Feb 15, 2018 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants