127 lines
4.2 KiB
C#
127 lines
4.2 KiB
C#
/*
|
|
* Copyright 2016 The Cartographer Authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace CartographerSharp.Common.Time;
|
|
|
|
/// <summary>
|
|
/// Universal Time Scale clock for Cartographer.
|
|
/// Represents durations and timestamps as 64-bit integers representing
|
|
/// 100 nanosecond ticks since the Epoch (January 1, 1 at the start of day in UTC).
|
|
/// </summary>
|
|
public static partial class TimeUtils
|
|
{
|
|
/// <summary>
|
|
/// UTS Epoch offset from Unix Epoch in seconds.
|
|
/// </summary>
|
|
public const long UtsEpochOffsetFromUnixEpochInSeconds = 719162L * 24L * 60L * 60L;
|
|
|
|
/// <summary>
|
|
/// Ticks per second in Universal Time Scale (100 nanoseconds = 10,000,000 ticks per second).
|
|
/// </summary>
|
|
public const long TicksPerSecond = 10_000_000L;
|
|
|
|
/// <summary>
|
|
/// Creates a Duration from seconds.
|
|
/// </summary>
|
|
public static TimeSpan FromSeconds(double seconds)
|
|
{
|
|
return TimeSpan.FromTicks((long)(seconds * TicksPerSecond));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a Duration from milliseconds.
|
|
/// </summary>
|
|
public static TimeSpan FromMilliseconds(long milliseconds)
|
|
{
|
|
// Convert milliseconds to 100-nanosecond ticks (1 ms = 10,000 ticks)
|
|
// This matches the C++ implementation: std::chrono::duration_cast<Duration>(std::chrono::milliseconds(milliseconds))
|
|
return TimeSpan.FromTicks(milliseconds * 10_000L);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the given duration in seconds.
|
|
/// </summary>
|
|
public static double ToSeconds(TimeSpan duration)
|
|
{
|
|
return duration.TotalSeconds;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a Time from Universal Time Scale ticks.
|
|
/// </summary>
|
|
public static DateTime FromUniversal(long ticks)
|
|
{
|
|
// Universal Time Scale epoch is January 1, 1 at the start of day in UTC
|
|
// We need to convert from UTS epoch to .NET DateTime epoch (January 1, 0001)
|
|
// UTS epoch offset: 719162 days = January 1, 1
|
|
// .NET DateTime epoch: January 1, 0001
|
|
// So we can use DateTime directly since both use the same epoch
|
|
return new DateTime(ticks, DateTimeKind.Utc);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Outputs the Universal Time Scale timestamp for a given Time.
|
|
/// </summary>
|
|
public static long ToUniversal(DateTime time)
|
|
{
|
|
return time.ToUniversalTime().Ticks;
|
|
}
|
|
|
|
/// <summary>
|
|
/// CPU time consumed by the thread so far, in seconds.
|
|
/// </summary>
|
|
public static double GetThreadCpuTimeSeconds()
|
|
{
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
{
|
|
// Windows implementation would use GetThreadTimes
|
|
// For now, return 0 on Windows
|
|
return 0.0;
|
|
}
|
|
else
|
|
{
|
|
// Linux implementation using clock_gettime with CLOCK_THREAD_CPUTIME_ID
|
|
var timespec = new Timespec();
|
|
if (clock_gettime(ClockId.CLOCK_THREAD_CPUTIME_ID, ref timespec) == 0)
|
|
{
|
|
return timespec.tv_sec + 1e-9 * timespec.tv_nsec;
|
|
}
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct Timespec
|
|
{
|
|
public long tv_sec; // seconds
|
|
public long tv_nsec; // nanoseconds
|
|
}
|
|
|
|
private enum ClockId
|
|
{
|
|
CLOCK_REALTIME = 0,
|
|
CLOCK_MONOTONIC = 1,
|
|
CLOCK_PROCESS_CPUTIME_ID = 2,
|
|
CLOCK_THREAD_CPUTIME_ID = 3,
|
|
CLOCK_MONOTONIC_RAW = 4,
|
|
}
|
|
|
|
[LibraryImport("libc", SetLastError = true)]
|
|
private static partial int clock_gettime(ClockId clockid, ref Timespec tp);
|
|
}
|