有没有办法从 C# 调用 RDTSC 汇编指令?

2023-11-27

我想要为我的 C# 应用程序提供一个非常高分辨率的计时器。我想访问 RDTSC 汇编指令。有没有办法做到这一点?

编辑:我正在移植一些 C++ 代码并尝试保留与原始代码相同的功能。我可能会切换到更 .NET 的东西,但想要评估 RDTSC 指令,以便我可以将结果与原始结果进行比较。


您可以这样做:

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;

public static class Rdtsc
{
    [StructLayout(LayoutKind.Sequential)]
    private struct SystemInfo
    {
        public ushort wProcessorArchitecture;
        public ushort wReserved;
        public uint dwPageSize;
        public IntPtr lpMinimumApplicationAddress;
        public IntPtr lpMaximumApplicationAddress;
        public IntPtr dwActiveProcessorMask;
        public uint dwNumberOfProcessors;
        public uint dwProcessorType;
        public uint dwAllocationGranularity;
        public ushort wProcessorLevel;
        public ushort wProcessorRevision;
    }

    [DllImport("kernel32.dll", ExactSpelling = true)]
    private static extern void GetNativeSystemInfo(out SystemInfo lpSystemInfo);

    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);

    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);

    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);

    private const uint PAGE_READWRITE = 0x04;
    private const uint PAGE_EXECUTE = 0x10;
    private const uint MEM_COMMIT = 0x1000;
    private const uint MEM_RELEASE = 0x8000;

    [SuppressUnmanagedCodeSecurity]
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate ulong TimestampDelegate();

    public static readonly TimestampDelegate Timestamp;

    static Rdtsc()
    {
        SystemInfo systemInfo;
        GetNativeSystemInfo(out systemInfo);

        if (systemInfo.wProcessorArchitecture != 0 /* PROCESSOR_ARCHITECTURE_INTEL */ && 
            systemInfo.wProcessorArchitecture != 9 /* PROCESSOR_ARCHITECTURE_AMD64 */)
        {
            // Fallback for ARM/IA64/...
            Timestamp = StopwatchGetTimestamp;
            return;
        }

        byte[] body;

        if (Environment.Is64BitProcess)
        {
            body = new byte[] 
            {
                0x0f, 0x31, // rdtsc
                0x48, 0xc1, 0xe2, 0x20, // shl rdx,20h 
                0x48, 0x0b, 0xc2, // or rax,rdx 
                0xc3, // ret
            };
        }
        else
        {
            body = new byte[] 
            {
                0x0f, 0x31, // rdtsc
                0xc3, // ret
            };
        }

        IntPtr buf = IntPtr.Zero;

        try
        {
            // We VirtualAlloc body.Length bytes, with R/W access
            // Note that from what I've read, MEM_RESERVE is useless
            // if the first parameter is IntPtr.Zero
            buf = VirtualAlloc(IntPtr.Zero, (IntPtr)body.Length, MEM_COMMIT, PAGE_READWRITE);

            if (buf == IntPtr.Zero)
            {
                throw new Win32Exception();
            }

            // Copy our instructions in the buf
            Marshal.Copy(body, 0, buf, body.Length);

            // Change the access of the allocated memory from R/W to Execute
            uint oldProtection;
            bool result = VirtualProtect(buf, (IntPtr)body.Length, PAGE_EXECUTE, out oldProtection);

            if (!result)
            {
                throw new Win32Exception();
            }

            // Create a delegate to the "function"
            Timestamp = (TimestampDelegate)Marshal.GetDelegateForFunctionPointer(buf, typeof(TimestampDelegate));

            buf = IntPtr.Zero;
        }
        finally
        {
            // There was an error!
            if (buf != IntPtr.Zero)
            {
                // Free the allocated memory
                bool result = VirtualFree(buf, IntPtr.Zero, MEM_RELEASE);

                if (!result)
                {
                    throw new Win32Exception();
                }
            }
        }
    }

    // Fallback if rdtsc isn't available
    private static ulong StopwatchGetTimestamp()
    {
        return unchecked((ulong)Stopwatch.GetTimestamp());
    }
}

一些注意事项:

  • 我已经包含了 ARM 处理器的后备方案(Stopwatch.GetTimestamp()).
  • I'm not使用 CPUID 来阻止 RDTSC 指令被移动(“cpuid”位于“rdtsc”之前)。我不擅长组装,所以我不知道该怎么做。如果您想修改代码,请随意修改并在要使用的“正确”操作码上添加注释
  • 我正在使用 RDTSC 并且notRDTSCP(同样的问题,汇编不是我的语言)
  • It is very慢...假设在 RDTSC 的 18-24 个滴答内调用了等效的 Visual C++ 代码,而没有内联,而在初始预热之后,在 RDTSC 的 27-100 个滴答内调用了 C# 版本。

Visual C++比较代码:

__declspec(noinline) uint64_t __stdcall Rdtsc(void)
{
    return __rdtsc();
}

啊啊啊现在...使用 rdtscp 全面实施

public static class Rdtsc
{
    [StructLayout(LayoutKind.Sequential)]
    private struct SystemInfo
    {
        public ushort wProcessorArchitecture;
        public ushort wReserved;
        public uint dwPageSize;
        public IntPtr lpMinimumApplicationAddress;
        public IntPtr lpMaximumApplicationAddress;
        public IntPtr dwActiveProcessorMask;
        public uint dwNumberOfProcessors;
        public uint dwProcessorType;
        public uint dwAllocationGranularity;
        public ushort wProcessorLevel;
        public ushort wProcessorRevision;
    }

    [DllImport("kernel32.dll", ExactSpelling = true)]
    private static extern void GetNativeSystemInfo(out SystemInfo lpSystemInfo);

    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);

    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);

    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);

    private const uint PAGE_READWRITE = 0x04;
    private const uint PAGE_EXECUTE = 0x10;
    private const uint PAGE_EXECUTE_READWRITE = 0x40;
    private const uint MEM_COMMIT = 0x1000;
    private const uint MEM_RELEASE = 0x8000;

    [SuppressUnmanagedCodeSecurity]
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate ulong FuncUInt64();

    /// <summary>
    /// Uses rdtsc. On non-Intel uses Stopwatch.GetTimestamp.
    /// </summary>
    public static readonly FuncUInt64 Timestamp;

    /// <summary>
    /// Uses rdtscp if present. Otherwise uses cpuid + rdtsc. On 
    /// non-Intel uses Stopwatch.GetTimestamp.
    /// </summary>
    public static readonly FuncUInt64 TimestampP;

    public static readonly bool IsRdtscSupported;
    public static readonly bool IsRdtscPSupported;

    static Rdtsc()
    {
        SystemInfo systemInfo;
        GetNativeSystemInfo(out systemInfo);

        if (systemInfo.wProcessorArchitecture != 0 /* PROCESSOR_ARCHITECTURE_INTEL */ && 
            systemInfo.wProcessorArchitecture != 9 /* PROCESSOR_ARCHITECTURE_AMD64 */)
        {
            // Fallback for ARM/IA64/...
            Timestamp = StopwatchGetTimestamp;
            TimestampP = StopwatchGetTimestamp;
            IsRdtscSupported = false;
            IsRdtscPSupported = false;
            return;
        }

        byte[] cpuid, rdtsc, rdtscp, rdtsccpuid;

        IsRdtscSupported = true;

        // Assembly generated with https://defuse.ca/online-x86-assembler.htm

        if (Environment.Is64BitProcess)
        {
            /* CPUID x64:
                    push rbx;
                    mov eax, 0x80000000;
                    cpuid;
                    mov ebx, 0x80000001;
                    cmp eax, ebx;
                    jb Error;
                    mov eax, ebx;
                    cpuid;
                    mov eax, ecx;
                    shl rax, 0x20;
                    or rax, rdx
                    jmp End;
                Error:
                    xor rax, rax;
                End:
                    pop rbx;
                    ret;

                0:  53                      push   rbx
                1:  b8 00 00 00 80          mov    eax,0x80000000
                6:  0f a2                   cpuid
                8:  bb 01 00 00 80          mov    ebx,0x80000001
                d:  39 d8                   cmp    eax,ebx
                f:  72 0f                   jb     20 <Error>
                11: 89 d8                   mov    eax,ebx
                13: 0f a2                   cpuid
                15: 89 c8                   mov    eax,ecx
                17: 48 c1 e0 20             shl    rax,0x20
                1b: 48 09 d0                or     rax,rdx
                1e: eb 03                   jmp    23 <End>
                0000000000000020 <Error>:
                20: 48 31 c0                xor    rax,rax
                0000000000000023 <End>:
                23: 5b                      pop    rbx
                24: c3                      ret
             */
            cpuid = new byte[] { 0x53, 0xB8, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xA2, 0xBB, 0x01, 0x00, 0x00, 0x80, 0x39, 0xD8, 0x72, 0x16, 0x89, 0xD8, 0x48, 0xC7, 0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xA2, 0x89, 0xC8, 0x48, 0xC1, 0xE0, 0x20, 0x48, 0x09, 0xD0, 0xEB, 0x03, 0x48, 0x31, 0xC0, 0x5B, 0xC3 };

            /* RDTSC x64:
                rdtsc;
                shl rdx, 0x20;
                or rax,rdx;
                ret;

                0:  0f 31                   rdtsc
                2:  48 c1 e2 20             shl    rdx,0x20
                6:  48 09 d0                or     rax,rdx
                9:  c3                      ret
             */
            rdtsc = new byte[] { 0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3 };

            /* RDTSCP x64
                rdtscp;
                shl rdx, 0x20;
                or rax, rdx;
                ret;

                0:  0f 01 f9                rdtscp
                3:  48 c1 e2 20             shl    rdx,0x20
                7:  48 09 d0                or     rax,rdx
                a:  c3                      ret
             */
            rdtscp = new byte[] { 0x0F, 0x01, 0xF9, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3 };

            /* RDTSC + CPUID x64
                push rbx;
                xor eax, eax;
                cpuid;
                rdtsc;
                shl rdx, 0x20;
                or rax, rdx;
                pop rbx;
                ret;

                0:  53                      push   rbx
                1:  31 c0                   xor    eax,eax
                3:  0f a2                   cpuid
                5:  0f 31                   rdtsc
                7:  48 c1 e2 20             shl    rdx,0x20
                b:  48 09 d0                or     rax,rdx
                e:  5b                      pop    rbx
                f:  c3                      ret
             */
            rdtsccpuid = new byte[] { 0x53, 0x31, 0xC0, 0x0F, 0xA2, 0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0x5B, 0xC3 };
        }
        else
        {
            /* CPUID x86:
                    push ebx;
                    mov eax, 0x80000000;
                    cpuid;
                    mov ebx, 0x80000001;
                    cmp eax, ebx;
                    jb Error;
                    mov eax, ebx;
                    cpuid;
                    mov eax, edx;
                    mov edx, ecx;
                    jmp End;
                Error:
                    xor eax, eax;
                    xor edx, edx;
                End:
                    pop ebx;
                    ret;

                0:  53                      push   ebx
                1:  b8 00 00 00 80          mov    eax,0x80000000
                6:  0f a2                   cpuid
                8:  bb 01 00 00 80          mov    ebx,0x80000001
                d:  39 d8                   cmp    eax,ebx
                f:  72 0a                   jb     1b <Error>
                11: 89 d8                   mov    eax,ebx
                13: 0f a2                   cpuid
                15: 89 d0                   mov    eax,edx
                17: 89 ca                   mov    edx,ecx
                19: eb 04                   jmp    1f <End>
                0000001b <Error>:
                1b: 31 c0                   xor    eax,eax
                1d: 31 d2                   xor    edx,edx
                0000001f <End>:
                1f: 5b                      pop    ebx
                20: c3                      ret
            */
            cpuid = new byte[] { 0x53, 0xB8, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xA2, 0xBB, 0x01, 0x00, 0x00, 0x80, 0x39, 0xD8, 0x72, 0x0A, 0x89, 0xD8, 0x0F, 0xA2, 0x89, 0xD0, 0x89, 0xCA, 0xEB, 0x04, 0x31, 0xC0, 0x31, 0xD2, 0x5B, 0xC3 };

            /* RDTSC x86:
                rdtsc;
                ret;

                0:  0f 31                   rdtsc
                2:  c3                      ret
             */
            rdtsc = new byte[] { 0x0F, 0x31, 0xC3 };

            /* RDTSCP x86
                rdtscp;
                ret;

                0:  0f 01 f9                rdtscp
                3:  c3                      ret
             */
            rdtscp = new byte[] { 0x0F, 0x01, 0xF9, 0xC3 };

            /* RDTSC + CPUID x86
                push ebx;
                xor eax,eax;
                cpuid;
                rdtsc;
                pop ebx;
                ret;

                0:  53                      push   ebx
                1:  31 c0                   xor    eax,eax
                3:  0f a2                   cpuid
                5:  0f 31                   rdtsc
                7:  5b                      pop    ebx
                8:  c3                      ret
             */
            rdtsccpuid = new byte[] { 0x53, 0x31, 0xC0, 0x0F, 0xA2, 0x0F, 0x31, 0x5B, 0xC3 };
        }

        IntPtr buf = IntPtr.Zero;

        try
        {
            // We pad the functions to 64 bytes (the length of a cache
            // line on the Intel processors)
            int cpuidLength = (cpuid.Length & 63) != 0 ? (cpuid.Length | 63) + 1 : cpuid.Length;
            int rdtscLength = (rdtsc.Length & 63) != 0 ? (rdtsc.Length | 63) + 1 : rdtsc.Length;
            int rdtscpLength = (rdtscp.Length & 63) != 0 ? (rdtscp.Length | 63) + 1 : rdtscp.Length;
            int rdtsccpuidLength = (rdtsccpuid.Length & 63) != 0 ? (rdtsccpuid.Length | 63) + 1 : rdtsccpuid.Length;

            // We don't know which one of rdtscp or rdtsccpuid we will
            // use, so we calculate space for the biggest one.
            // Note that it is very unlikely that we will go over 4096
            // bytes (the minimum size of memory allocated by 
            // VirtualAlloc)
            int totalLength = cpuidLength + rdtscLength + Math.Max(rdtscpLength, rdtsccpuidLength);

            // We VirtualAlloc totalLength bytes, with R/W access
            // Note that from what I've read, MEM_RESERVE is useless
            // if the first parameter is IntPtr.Zero
            buf = VirtualAlloc(IntPtr.Zero, (IntPtr)totalLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

            if (buf == IntPtr.Zero)
            {
                throw new Win32Exception();
            }

            // Copy cpuid instructions in the buf
            Marshal.Copy(cpuid, 0, buf, cpuid.Length);

            for (int i = cpuid.Length; i < cpuidLength; i++)
            {
                Marshal.WriteByte(buf, i, 0x90); // nop
            }

            // Copy rdtsc instructions in the buf
            Marshal.Copy(rdtsc, 0, buf + cpuidLength, rdtsc.Length);

            for (int i = rdtsc.Length; i < rdtscLength; i++)
            {
                Marshal.WriteByte(buf, cpuidLength + i, 0x90); // nop
            }

            var cpuidFunc = (FuncUInt64)Marshal.GetDelegateForFunctionPointer(buf, typeof(FuncUInt64));

            // We use cpuid, EAX=0x80000001 to check for the rdtscp
            ulong supportedFeatures = cpuidFunc();

            byte[] rdtscpSelected;
            int rdtscpSelectedLength;

            // Check the rdtscp flag
            if ((supportedFeatures & (1L << 27)) != 0)
            {
                // rdtscp supported
                rdtscpSelected = rdtscp;
                rdtscpSelectedLength = rdtscpLength;
                IsRdtscPSupported = true;
            }
            else
            {
                // rdtscp not supported. We use cpuid + rdtsc
                rdtscpSelected = rdtsccpuid;
                rdtscpSelectedLength = rdtsccpuidLength;
                IsRdtscPSupported = false;
            }

            // Copy rdtscp/rdtsccpuid instructions in the buf
            Marshal.Copy(rdtscpSelected, 0, buf + cpuidLength + rdtscLength, rdtscpSelected.Length);

            for (int i = rdtscpSelected.Length; i < rdtscpSelectedLength; i++)
            {
                Marshal.WriteByte(buf, cpuidLength + rdtscLength + i, 0x90); // nop
            }

            // Change the access of the allocated memory from R/W to Execute
            uint oldProtection;
            bool result = VirtualProtect(buf, (IntPtr)totalLength, PAGE_EXECUTE, out oldProtection);

            if (!result)
            {
                throw new Win32Exception();
            }

            // Create a delegate to the "function"
            Timestamp = (FuncUInt64)Marshal.GetDelegateForFunctionPointer(buf + cpuidLength, typeof(FuncUInt64));
            TimestampP = (FuncUInt64)Marshal.GetDelegateForFunctionPointer(buf + cpuidLength + rdtscLength, typeof(FuncUInt64));

            buf = IntPtr.Zero;
        }
        finally
        {
            // There was an error!
            if (buf != IntPtr.Zero)
            {
                // Free the allocated memory
                bool result = VirtualFree(buf, IntPtr.Zero, MEM_RELEASE);

                if (!result)
                {
                    throw new Win32Exception();
                }
            }
        }
    }

    // Fallback if rdtsc isn't available. We can't use directly
    // Stopwatch.GetTimestamp() because the return type is different.
    private static ulong StopwatchGetTimestamp()
    {
        return unchecked((ulong)Stopwatch.GetTimestamp());
    }
}

它更长...有两种方法,

ulong ts1 = Rdtsc.Timestamp();
ulong ts2 = Rdtsc.TimestampP();

第一个使用rdtsc,而第二个使用rdtscp. rdtscprdtsc因为它没有在管道中重新排序。这TimestampP方法一有一个针对旧处理器的后备方案,使用cpuid + rdtsc,但回退速度相当慢。对于这两种情况,非 Intel/AMD 处理器都有一个后备方案,使用Stopwatch.GetTimestamp()。该类在内部使用cpuid检查是否存在的指令rdtscp操作说明。有两个字段,IsRdtscSupported and IsRdtscPSupported告诉处理器是否支持rdtsc and rdtscp.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有没有办法从 C# 调用 RDTSC 汇编指令? 的相关文章

随机推荐

  • 创建单个 python 可执行模块

    伙计们 我在模块中有很多 python 代码 这些代码驻留在多个 python 包中 现在我需要创建单个 python 可执行模块或文件 其中将包含所有这些文件 因此它将在 Windows 和 Linux 服务器上运行 有哪些可能的解决方案
  • 用默认值初始化字段是多余的

    我真的可以信任 NET 来初始化字段 如整数 结构等 吗 如果我仍然想初始化这些字段怎么办 会产生什么影响 The C 规范第 305 页上的说明 17 4 4 字段的初始值 无论是静态字段还是实例字段 都是该字段的默认值 第 12 2 节
  • GWT 日志记录设置

    我正在使用 GWT 2 1 java util logging仿真记录客户端消息 根据文档 提供了两个适用于客户端日志记录的格式化程序 TextFormatter 和 HTMLFormatter 任何人都可以提供有关如何设置格式化程序并将其
  • 我正在尝试复制文件,但收到错误消息

    我是 postgres 的新手 可能缺少一些愚蠢的东西 例如 我的目录的正确名称 有人可以指导我吗 我正在遵循 Anthony DeBarros 的 实用 SQL 一书的说明 Code copy us counties 2010 from
  • easy_install-2.7 的问题

    安装 easy install 并尝试使用它来安装 python 包后 它失败了 root server easy install 2 7 pip Searching for pip Reading http pypi python org
  • android 设置特定时间通知

    我意识到这个问题以前已经被问过 但我对这个问题一筹莫展 我有一个警报管理器来设置通知 public void to reminder View view Intent intent new Intent this Notification
  • 从向量创建Mat

    我对计算机视觉和 opencv 库非常陌生 我已经进行了一些谷歌搜索 试图找到如何从 Point2fs 向量制作新图像 但没有找到任何有效的示例 我见过vector
  • Java 和 Mojave 的强化运行时

    我目前分发一个 Java 应用程序 打包并签名 using pkgbuild在 macOS 上 最近 苹果警告开发者 在即将发布的 macOS 版本中 Gatekeeper 将要求开发人员 ID 签名的软件经过公证的由苹果公司 阅读公证文件
  • 使用 numpy 滚动最大值

    这计算了 滚动最大值 A 类似于滚动平均值 在长度的滑动窗口上K import numpy as np A np random rand 100000 K 10 rollingmax np array max A j j K for j i
  • 在 C++ 中返回一个数组

    假设我有一个数组 int arr arr function arr 我的功能是 int function int arr rest of the code return arr 我在这里犯了什么错误 int function int arr
  • C++,使用#if TRUE 条件指令

    当使用像这样的语句时 if TRUE 我应该期待发生什么 如有解释 将不胜感激 我明白如何 if 1有效 但它给出了完全地我的代码中的结果与使用不同 if TRUE 我明白 if是一个条件指令 以及它意味着什么 这只是TRUE or FAL
  • Pipenv 无法识别 Pyenv 版本?

    我安装了 Python 3 7 0 但对于特定的 Django 项目 我想使用 Python 3 6 5 使用pyenv为此 我在 Macbook Pro 上运行了brew install pyenv 其次是pyenv install 3
  • 从父级导航嵌入的 Google Apps 脚本 iFrame

    我有一个多页网络应用程序 我希望登录后 用户可以看到他的队友列表并标记他们的出勤状态 我的问题是我无法在 iFrame 中显示这一点 而不是在 google 脚本原始框架中显示这一点 例如 我想将其 iFrame 到我自己的网页上 这两天我
  • 使用 ASP.NET MVC 2 上传文件的最佳方式是什么?

    上传可变大小的文件 对于 ASP NET MVC 2 应用程序文件系统来说非常大或非常小 的最佳方法是什么 到目前为止我的理解是这样的 人们似乎有两种处理这个问题的方法 假设文件可能非常大或非常小 1 在控制器操作中处理上传Request
  • jQuery:同一事件有多个处理程序

    如果我将两个事件处理程序绑定到同一元素的同一事件 会发生什么情况 例如 var elem elem click elem click 最后一个处理程序 获胜 还是两个处理程序都会运行 两个处理程序都将运行 jQuery 事件模型允许在一个元
  • Angular 4:日期管道,UTC 时间到本地时间:如何告诉 Angular 当前时区?

    我们将 Angular 4 与用 net core 编写的 MVC 应用程序一起使用 使用 SignalR 服务接收数据 集线器是用 C 编写的 数据库提供 Datetime2 7 字段 T SQL 收到的内容如下所示 对于日期字段 due
  • SQL FileStream + Entity Framework 存储大文件

    当我想将文件存储在文件流列中时 我总是需要将整个二进制文件读入内存 using MemoryStream memoryStream new MemoryStream sourceStream CopyTo memoryStream bina
  • 在 PHP 中解析 javascript 数组

    我似乎不知道如何将 JS 数组放入 PHP 中 我必须处理的事情看起来像这样 var arrLow e 495864 rank 8678591 rankmove p img src up php uStyle 144 UP 495864 e
  • “Create VIEW”必须是批处理中的唯一语句

    我有以下 SQL ALTER PROCEDURE dbo usp gettasks ID varchar 50 AS declare PDate Date WHILE DATEPART DW PDate 1 OR DATEPART DW P
  • 有没有办法从 C# 调用 RDTSC 汇编指令?

    我想要为我的 C 应用程序提供一个非常高分辨率的计时器 我想访问 RDTSC 汇编指令 有没有办法做到这一点 编辑 我正在移植一些 C 代码并尝试保留与原始代码相同的功能 我可能会切换到更 NET 的东西 但想要评估 RDTSC 指令 以便