//
// Copyright (c) 2004-2006 Jaroslaw Kowalski <jaak@jkowalski.net>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of Jaroslaw Kowalski nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//
using System;
using System.Text;
using System.Globalization;
using System.Security;
using System.Runtime.InteropServices;
using NLog.Config;
namespace NLog.LayoutRenderers
{
/// <summary>
/// High precision timer, based on the value returned from QueryPerformanceCounter() optionally converted to seconds.
/// </summary>
[LayoutRenderer("qpc")]
[SupportedRuntime(OS=RuntimeOS.Windows)]
[SupportedRuntime(OS=RuntimeOS.WindowsNT)]
[SupportedRuntime(OS=RuntimeOS.WindowsCE)]
public class QpcLayoutRenderer: LayoutRenderer
{
private bool _raw = false;
private bool _normalize = true;
private bool _diff = false;
private ulong _firstQpcValue = 0;
private ulong _lastQpcValue = 0;
private bool _first = true;
private double _frequency = 1;
private int _precision = 6;
private bool _alignDecimalPoint = true;
/// <summary>
/// Normalize the result by subtracting it from the result of the
/// first call (so that it's effectively zero-based).
/// </summary>
[System.ComponentModel.DefaultValue(true)]
private bool Normalize
{
get { return _normalize; }
set { _normalize = value; }
}
/// <summary>
/// Output the difference between the result of QueryPerformanceCounter
/// and the previous one.
/// </summary>
[System.ComponentModel.DefaultValue(false)]
private bool Difference
{
get { return _diff; }
set { _diff = value; }
}
/// <summary>
/// Convert the result to seconds by dividing by the result of QueryPerformanceFrequency().
/// </summary>
[System.ComponentModel.DefaultValue(true)]
public bool Seconds
{
get { return !_raw; }
set { _raw = !value; }
}
/// <summary>
/// Number of decimal digits to be included in output.
/// </summary>
[System.ComponentModel.DefaultValue(4)]
public int Precision
{
get { return _precision; }
set { _precision = value; }
}
/// <summary>
/// Align decimal point (emit non-significant zeros)
/// </summary>
[System.ComponentModel.DefaultValue(true)]
public bool AlignDecimalPoint
{
get { return _alignDecimalPoint; }
set { _alignDecimalPoint = value; }
}
/// <summary>
/// Returns the estimated number of characters that are needed to
/// hold the rendered value for the specified logging event.
/// </summary>
/// <param name="logEvent">Logging event information.</param>
/// <returns>The number of characters.</returns>
/// <remarks>
/// If the exact number is not known or
/// expensive to calculate this function should return a rough estimate
/// that's big enough in most cases, but not too big, in order to conserve memory.
/// </remarks>
protected internal override int GetEstimatedBufferSize(LogEventInfo logEvent)
{
return 32;
}
/// <summary>
/// Renders the ticks value of current time and appends it to the specified <see cref="StringBuilder" />.
/// </summary>
/// <param name="builder">The <see cref="StringBuilder"/> to append the rendered data to.</param>
/// <param name="logEvent">Logging event.</param>
protected internal override void Append(StringBuilder builder, LogEventInfo logEvent)
{
ulong qpcValue;
if (!QueryPerformanceCounter(out qpcValue))
return;
if (_first)
{
lock (this)
{
if (_first)
{
ulong frequency;
QueryPerformanceFrequency(out frequency);
_frequency = (double)frequency;
_firstQpcValue = qpcValue;
_lastQpcValue = qpcValue;
_first = false;
}
}
}
ulong v = qpcValue;
if (Difference)
qpcValue -= _lastQpcValue;
else if (Normalize)
qpcValue -= _firstQpcValue;
_lastQpcValue = v;
string stringValue;
if (Seconds)
{
double val = Math.Round((double)qpcValue / _frequency, Precision);
stringValue = Convert.ToString(val, CultureInfo.InvariantCulture);
if (AlignDecimalPoint)
{
int p = stringValue.IndexOf('.');
if (p == -1)
{
stringValue += "." + new string('0', Precision);
}
else
{
stringValue += new string('0', Precision - (stringValue.Length - 1 - p));
}
}
}
else
{
stringValue = Convert.ToString(qpcValue);
}
builder.Append(ApplyPadding(stringValue));
}
#if !NETCF
[DllImport("kernel32.dll"), SuppressUnmanagedCodeSecurity]
#else
[DllImport("coredll.dll")]
#endif
static extern bool QueryPerformanceCounter(out ulong lpPerformanceCount);
#if !NETCF
[DllImport("kernel32.dll"), SuppressUnmanagedCodeSecurity]
#else
[DllImport("coredll.dll")]
#endif
static extern bool QueryPerformanceFrequency(out ulong lpPerformanceFrequency);
}
}