I would like to write a tool in C# which can detect the presence of multiple CPU groups in Windows. I have seen this referred to as kGroups, and also as NUMA nodes.
This need has grown out of multiple performance related issues where we discovered the customer was running HP servers which often have their NUMA Group Size Optimization in the BIOS set to "Clustered" instead of "Flat" which can result in multiple CPU groups in Windows. Any one process, unless otherwise designed to operate across kGroups, will only be able to use logical processors within the kGroup the process affinity is set to.
I have found a number of resources that can detect information about number of physical/logical processors, but I'm unable to find information on if/how those CPU's might be logically grouped. I'm open to getting this info through p/invoke or WMI among other methods.
Edit: Found the following post with a full example of the GetLogicalProcessorInformationEx call via p/invoke. Will update when I can confirm how to test numa node configuration.
https://stackoverflow.com/a/6972620/3736007
references: http://h17007.www1.hpe.com/docs/iss/proliant_uefi/UEFI_Gen9_060216/s_set_NUMA_group.html
Solved (I think). I was able to use David Heffernan's c# implementation, wrapped it up in a class and added some properties to return some of the information I'm after. Unsafe code is still a bit of black magic to me so I know it could be done better, but it's working so far.
public static class LogicalProcessorInformation
{
public static int CpuPackages
{
get
{
if (_buffer == null)
_buffer = MyGetLogicalProcessorInformation();
return _buffer.Count(b => b.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorPackage);
}
}
public static int CpuCores
{
get
{
if (_buffer == null)
_buffer = MyGetLogicalProcessorInformation();
return _buffer.Count(b => b.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore);
}
}
public static int LogicalProcessors
{
get
{
if (_buffer == null)
_buffer = MyGetLogicalProcessorInformation();
var count = 0;
foreach (var obj in _buffer.Where(b => b.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore))
{
count += CountSetBits(obj.ProcessorMask);
}
return count;
}
}
public static int CpuGroups
{
get
{
if (_buffer == null)
_buffer = MyGetLogicalProcessorInformation();
return _buffer.Count(b => b.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup);
}
}
public static int NumaNodes
{
get
{
if (_buffer == null)
_buffer = MyGetLogicalProcessorInformation();
return _buffer.Count(b => b.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationNumaNode);
}
}
private static int CountSetBits(UIntPtr bitMask)
{
// todo: get rid of tostring and figure out the right way.
var bitMaskuint = uint.Parse(bitMask.ToString());
uint count = 0;
while (bitMaskuint != 0)
{
count += bitMaskuint & 1;
bitMaskuint >>= 1;
}
return (int)count;
}
private static SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] _buffer;
[StructLayout(LayoutKind.Sequential)]
private struct PROCESSORCORE
{
public byte Flags;
};
[StructLayout(LayoutKind.Sequential)]
private struct NUMANODE
{
public uint NodeNumber;
}
private enum PROCESSOR_CACHE_TYPE
{
CacheUnified,
CacheInstruction,
CacheData,
CacheTrace
}
[StructLayout(LayoutKind.Sequential)]
private struct CACHE_DESCRIPTOR
{
public byte Level;
public byte Associativity;
public ushort LineSize;
public uint Size;
public PROCESSOR_CACHE_TYPE Type;
}
[StructLayout(LayoutKind.Explicit)]
private struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION
{
[FieldOffset(0)]
public PROCESSORCORE ProcessorCore;
[FieldOffset(0)]
public NUMANODE NumaNode;
[FieldOffset(0)]
public CACHE_DESCRIPTOR Cache;
[FieldOffset(0)]
private UInt64 Reserved1;
[FieldOffset(8)]
private UInt64 Reserved2;
}
private enum LOGICAL_PROCESSOR_RELATIONSHIP
{
RelationProcessorCore,
RelationNumaNode,
RelationCache,
RelationProcessorPackage,
RelationGroup,
RelationAll = 0xffff
}
private struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
{
public UIntPtr ProcessorMask;
public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
public SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION ProcessorInformation;
}
[DllImport(#"kernel32.dll", SetLastError = true)]
private static extern bool GetLogicalProcessorInformation(
IntPtr Buffer,
ref uint ReturnLength
);
private const int ERROR_INSUFFICIENT_BUFFER = 122;
private static SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] MyGetLogicalProcessorInformation()
{
uint ReturnLength = 0;
GetLogicalProcessorInformation(IntPtr.Zero, ref ReturnLength);
if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
{
IntPtr Ptr = Marshal.AllocHGlobal((int)ReturnLength);
try
{
if (GetLogicalProcessorInformation(Ptr, ref ReturnLength))
{
int size = Marshal.SizeOf(typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
int len = (int)ReturnLength / size;
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] Buffer = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[len];
IntPtr Item = Ptr;
for (int i = 0; i < len; i++)
{
Buffer[i] = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION)Marshal.PtrToStructure(Item, typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
Item += size;
}
return Buffer;
}
}
finally
{
Marshal.FreeHGlobal(Ptr);
}
}
return null;
}
}
Related
I have 2 programs written in c#, first one called "ScanMe" contains a string variable that contains value "FINDMEEEEEEE", and a double variable that has the value of 1546.22915487. And the other program called "MemoryScan" reads all the memory of the first program.
I want to get the memory address of the string variable of that process
When i execute "MemoryScan" and reads all the memory of "ScanMe" process, then i try to find the byte array of the string in all the data scanned and i get nothing. If i try to find the double i get the specific memory address and also i can change its value, but when i try to do that with the string variable i cant cause i dont even get the address of that string variable.
ScanMe and MemoryScan Code:
class Program
{
public static string FindMeString = "FINDMEEEEEEE";
public static double FindMeDouble = 1546.22915487;
static void Main(string[] args)
{
while (FindMeDouble == 1546.22915487)
{
System.Threading.Thread.Sleep(2000);
}
Console.WriteLine(FindMeDouble.ToString());
Console.ReadLine();
}
}
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace MemoryScan
{
class MemoryController
{
// REQUIRED CONSTS
const int PROCESS_QUERY_INFORMATION = 0x0400;
const int MEM_COMMIT = 0x00001000;
const int PAGE_READWRITE = 0x04;
const int PROCESS_WM_READ = 0x0010;
readonly Dictionary<IntPtr, byte[]> Regions = new Dictionary<IntPtr, byte[]>();
readonly List<SearchResult> _results = new List<SearchResult>();
// REQUIRED METHODS
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint dwSize, ref int lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
static extern void GetSystemInfo(out SystemInfo lpSystemInfo);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
public enum ProcessorArchitecture
{
X86 = 0,
X64 = 9,
Arm = -1,
Itanium = 6,
Unknown = 0xFFFF
}
// REQUIRED STRUCTS
[StructLayout(LayoutKind.Sequential)]
public struct SystemInfo
{
public ProcessorArchitecture ProcessorArchitecture;
public uint PageSize;
public IntPtr MinimumApplicationAddress;
public IntPtr MaximumApplicationAddress;
public IntPtr ActiveProcessorMask;
public uint NumberOfProcessors;
public uint ProcessorType;
public uint AllocationGranularity;
public ushort ProcessorLevel;
public ushort ProcessorRevision;
}
[StructLayout(LayoutKind.Sequential)]
public struct MEMORY_BASIC_INFORMATION
{
public IntPtr BaseAddress;
public IntPtr AllocationBase;
public uint AllocationProtect;
public IntPtr RegionSize;
public uint State;
public uint Protect;
public uint Type;
}
public void FindProcessMemory(int processId)
{
// getting minimum & maximum address
SystemInfo sys_info;
GetSystemInfo(out sys_info);
uint max_Address = (uint)sys_info.MaximumApplicationAddress;
// opening the process with desired access level
IntPtr processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_WM_READ, false, processId);
IntPtr current = IntPtr.Zero;
int bytesRead = 0; // number of bytes read with ReadProcessMemory
int dwLength = Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION));
while ((uint)current < max_Address && VirtualQueryEx(processHandle, current, out MEMORY_BASIC_INFORMATION mem_basic_info, dwLength) != 0)
{
// if this memory chunk is accessible
if (mem_basic_info.Protect == PAGE_READWRITE && mem_basic_info.State == MEM_COMMIT)
{
byte[] buffer = new byte[(int)mem_basic_info.RegionSize];
// read everything in the buffer above
if (ReadProcessMemory(processHandle, mem_basic_info.BaseAddress, buffer, (uint)mem_basic_info.RegionSize, ref bytesRead))
{
Regions.Add(mem_basic_info.BaseAddress, buffer);
}
else
Console.WriteLine($"Error code: Marshal.GetLastWin32Error()");
}
// move to the next memory chunk
current = IntPtr.Add(mem_basic_info.BaseAddress, mem_basic_info.RegionSize.ToInt32());
}
byte[] data = System.Text.Encoding.Unicode.GetBytes("FINDMEEEEEEE");
foreach (IntPtr address in Regions.Keys)
{
foreach (int i in ByteSearch.AllIndexOf(Regions[address], data))
_results.Add(new SearchResult(IntPtr.Add(address, i), data));
}
Console.ReadLine();
}
}
public static class ByteSearch
{
static int[] createTable(byte[] pattern)
{
int[] table = new int[256];
for (int i = 0; i < table.Length; i++)
table[i] = pattern.Length;
for (int i = 0; i < pattern.Length - 1; i++)
table[Convert.ToInt32(pattern[i])] = pattern.Length - i - 1;
return table;
}
public static bool matchAtOffset(byte[] toSearch, byte[] pattern, int index)
{
if (index + pattern.Length > toSearch.Length)
return false;
for (int i = 0; i < pattern.Length; i++)
{
if (toSearch[i + index] != pattern[i])
return false;
}
return true;
}
public static bool Contains(byte[] toSearch, byte[] pattern)
{
return FirstIndexOf(toSearch, pattern) != -1;
}
public static int FirstIndexOf(byte[] toSearch, byte[] pattern)
{
int[] table = createTable(pattern);
int position = pattern.Length - 1;
while (position < toSearch.Length)
{
int i;
for (i = 0; i < pattern.Length; i++)
{
if (pattern[pattern.Length - 1 - i] != toSearch[position - i])
break;
if (i == pattern.Length - 1)
return position - i;
}
position += table[Convert.ToInt32(toSearch[position - i])];
}
return -1;
}
public static int LastIndexOf(byte[] toSearch, byte[] pattern)
{
int ret = -1;
int[] table = createTable(pattern);
int position = pattern.Length - 1;
while (position < toSearch.Length)
{
int i;
bool found = false;
for (i = 0; i < pattern.Length; i++)
{
if (pattern[pattern.Length - 1 - i] != toSearch[position - i])
break;
if (i == pattern.Length - 1)
{
ret = position - i;
found = true;
}
}
if (found)
position++;
else
position += table[Convert.ToInt32(toSearch[position - i])];
}
return ret;
}
public static int[] AllIndexOf(byte[] toSearch, byte[] pattern)
{
List<int> indices = new List<int>();
int[] table = createTable(pattern);
int position = pattern.Length - 1;
while (position < toSearch.Length)
{
int i;
bool found = false;
for (i = 0; i < pattern.Length; i++)
{
if (pattern[pattern.Length - 1 - i] != toSearch[position - i])
break;
if (i == pattern.Length - 1)
{
indices.Add(position - i);
found = true;
}
}
if (found)
position++;
else
position += table[Convert.ToInt32(toSearch[position - i])];
}
return indices.ToArray();
}
}
public class SearchResult
{
public SearchResult(IntPtr add, byte[] value)
{
Address = add;
Buffer = value;
}
public IntPtr Address { get; set; }
public byte[] Buffer { get; set; }
}
}
Why i cant find the string and when i try to find the double i find it with no problem and even also i can change its value with the extern writeprocessmemory?
Thanks.
I'm not sure I could reproduce your exact condition, since you didn't provide a minimal reproducible example. However, I got it up and running - with similar results. I then figured out the following:
You are not checking the return value of ReadProcessMemory. MSDN says
If the function fails, the return value is 0 (zero). To get extended error information, call GetLastError.
The 0 will be mapped to false, depending on the PInvoke signature you use.
To get the last error, use Marshal.GetLastWin32Error(). On my PC, the error code was 299 and
MSDN says
ERROR_PARTIAL_COPY
299 (0x12B)
Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
At the same time, the number of bytes read (ref bytesRead) is 0, so it didn't read the process' memory.
See this related SO question about this error code.
Best way to describe the problem I'm trying to solve is to talk in code. I see a lot of __arglist questions on this forum, but not a lot of helpful answers. I know _arglist should be avoided so I'm open to alternative methods
In one C++ module I have something like the following
void SomeFunction(LPCWSTR pszFormat, va_args args)
{
// this function is not exported...
// it is designed to take a format specifier and a list of variable
// arguments and "printf" it into a buffer. This code
// allocates buffer and uses _vsnwprintf_s to format the
// string.
// I really do not have much flexibility to rewrite this function
// so please steer away from scrutinizing this. it is what is
// and I need to call it from C#.
::_vsnwprintf_s(somebuff, buffsize, _TRUNCATE, pszFormat, args)
}
__declspec(dllexport) void __cdecl ExportedSomeFunction(LPCWSTR pszFormat, ...)
{
// the purpose of this method is to export SomeFunction to C# code.
// it handles any marshaling. I can change this however it makes sense
va_list args ;
va_start(args, pszFormat) ;
SomeFunction(pszFormat, args) ;
va_end(args) ;
}
in another C# module I have code that handles all marshalling to the C++ DLL.
The intent is to hide all complexity of Native APIs and marshalling from user code.
The ultimate goal being a C++ developer or C# developer make the SAME API calls, but the code is written once and exported to both
[DllImport("mymodule.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern void ExportedSomeFunction(
[MarshalAs(UnmanagedType.LPWStr)] out string strPath,
/* ? what goes here ? */);
void SomeFunction(string strFormat, /*? what goes here ?*/ )
{
// handles marshalling incoming data to what ever is needed by exported C function
ExportedSomeFunction(strFormat, /*? something ?*/ ) ;
}
Then the user code in some other module should look like this...
SomeFunction("my format: %ld, %s", 5, "Some Useless string") ;
That would be ideal, but am prepared to live with
SomeFunction("my format: %ld, %s", __arglist(5, "Some Useless string")) ;
I don't care how the data gets marshaled. If I use __arglist or some array, I don't care as long as I end up with a va_args
__arglist looks like the solution, and I can successfully call
ExportedSomeFunction(strFormat, __arglist(5, "Some Useless string")) ;
But I cannot figure out how to call the C# SomeFunction with variable arguments and pass a __arglist to the exported function.
SomeFunction("my format: %ld, %s", __arglist(5, "Some Useless string")) ;
I cannot get this to work....
[DllImport("mymodule.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern void ExportedSomeFunction(
[MarshalAs(UnmanagedType.LPWStr)] out string strPath,
__arglist);
void SomeFunction(string strFormat, __arglist )
{
ExportedSomeFunction(strFormat, __arglist) ; // error cannot convert from RuntimeArgumentHandle to __arglist
}
This compiles, but doesn't produce the desired results. The argument list received in C++ is wrong.
private static extern void ExportedSomeFunction(
[MarshalAs(UnmanagedType.LPWStr)] out string strPath,
RuntimeArgumentHandle args);
Here is my suggestion how to tackle this. Take a look at varargs.h which is part of VisualStudio. This gives you some insight what the va_list means. You can see: typedef char * va_list;. It's just a pointer.
Not only is __arglist undocumented, I don't think it works correctly on 64-bit processes.
You need to build the va_list dynamically on C# side. I believe that this is better solution than undocumented __arglist and it seems to be working nicely. For C#, you want to use params[], and on C++ receiving side, va_list. Every variadic function should have function starting with v..., such as vsprintf, that receives va_list, instead of fiddling with arguments in the stack.
Copy/paste this beauty to your solution:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
// Author: Chris Eelmaa
namespace ConsoleApplication1
{
#region VariableCombiner
class CombinedVariables : IDisposable
{
readonly IntPtr _ptr;
readonly IList<IDisposable> _disposables;
bool _disposed;
public CombinedVariables(VariableArgument[] args)
{
_disposables = new List<IDisposable>();
_ptr = Marshal.AllocHGlobal(args.Sum(arg => arg.GetSize()));
var curPtr = _ptr;
foreach (var arg in args)
{
_disposables.Add(arg.Write(curPtr));
curPtr += arg.GetSize();
}
}
public IntPtr GetPtr()
{
if(_disposed)
throw new InvalidOperationException("Disposed already.");
return _ptr;
}
public void Dispose()
{
if (!_disposed)
{
_disposed = true;
foreach (var disposable in _disposables)
disposable.Dispose();
Marshal.FreeHGlobal(_ptr);
}
}
}
#endregion
#region VariableArgument
abstract class VariableArgument
{
#region SentinelDispose
protected static readonly IDisposable SentinelDisposable =
new SentinelDispose();
class SentinelDispose : IDisposable
{
public void Dispose()
{
}
}
#endregion
public abstract IDisposable Write(IntPtr buffer);
public virtual int GetSize()
{
return IntPtr.Size;
}
public static implicit operator VariableArgument(int input)
{
return new VariableIntegerArgument(input);
}
public static implicit operator VariableArgument(string input)
{
return new VariableStringArgument(input);
}
public static implicit operator VariableArgument(double input)
{
return new VariableDoubleArgument(input);
}
}
#endregion
#region VariableIntegerArgument
sealed class VariableIntegerArgument : VariableArgument
{
readonly int _value;
public VariableIntegerArgument(int value)
{
_value = value;
}
public override IDisposable Write(IntPtr buffer)
{
Marshal.Copy(new[] { _value }, 0, buffer, 1);
return SentinelDisposable;
}
}
#endregion
#region VariableDoubleArgument
sealed class VariableDoubleArgument : VariableArgument
{
readonly double _value;
public VariableDoubleArgument(double value)
{
_value = value;
}
public override int GetSize()
{
return 8;
}
public override IDisposable Write(IntPtr buffer)
{
Marshal.Copy(new[] { _value }, 0, buffer, 1);
return SentinelDisposable;
}
}
#endregion
#region VariableStringArgument
sealed class VariableStringArgument : VariableArgument
{
readonly string _value;
public VariableStringArgument(string value)
{
_value = value;
}
public override IDisposable Write(IntPtr buffer)
{
var ptr = Marshal.StringToHGlobalAnsi(_value);
Marshal.Copy(new[] {ptr}, 0, buffer, 1);
return new StringArgumentDisposable(ptr);
}
#region StringArgumentDisposable
class StringArgumentDisposable : IDisposable
{
IntPtr _ptr;
public StringArgumentDisposable(IntPtr ptr)
{
_ptr = ptr;
}
public void Dispose()
{
if (_ptr != IntPtr.Zero)
{
Marshal.FreeHGlobal(_ptr);
_ptr = IntPtr.Zero;
}
}
}
#endregion
}
#endregion
}
and the example of usage:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(
AmazingSPrintf("I am %s, %d years old, %f meters tall!",
"Chris",
24,
1.94));
}
static string AmazingSPrintf(string format, params VariableArgument[] args)
{
if (!args.Any())
return format;
using (var combinedVariables = new CombinedVariables(args))
{
var bufferCapacity = _vscprintf(format, combinedVariables.GetPtr());
var stringBuilder = new StringBuilder(bufferCapacity + 1);
vsprintf(stringBuilder, format, combinedVariables.GetPtr());
return stringBuilder.ToString();
}
}
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int vsprintf(
StringBuilder buffer,
string format,
IntPtr ptr);
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int _vscprintf(
string format,
IntPtr ptr);
}
}
The CombinedVariables class is used to build va_list, and then you can pass it to your C++ method void SomeFunction(LPCWSTR pszFormat, va_list args).
You need to take care of the VariableStringArgument as it works with ANSI currently. You're probably looking for Marshal.StringToHGlobalUni.
Note that there is a small difference between va_list and .... printf uses ..., while vprintf uses va_list. A va_list is often a pointer to the first element of the .... __arglist is for ....
For va_list you can use the code of #Erti, or my code:
public class VaList : IDisposable
{
protected readonly List<GCHandle> handles = new List<GCHandle>();
public VaList(bool unicode, params object[] args)
{
if (args == null)
{
throw new ArgumentNullException("args");
}
// The first handle is for the bytes array
handles.Add(default(GCHandle));
int total = 0;
var bytes = new PrimitiveToBytes[args.Length];
for (int i = 0; i < args.Length; i++)
{
int size = Convert(unicode, args[i], ref bytes[i]);
bytes[i].Size = size;
total += size;
}
// Instead of a byte[] we use a IntPtr[], so copying elements
// inside is faster (perhaps :-) )
var buffer = new IntPtr[total / IntPtr.Size];
handles[0] = GCHandle.Alloc(buffer, GCHandleType.Pinned);
for (int i = 0, j = 0; i < args.Length; i++)
{
buffer[j++] = bytes[i].IntPtr;
// long or double with IntPtr == 4
if (bytes[i].Size > IntPtr.Size)
{
buffer[j++] = (IntPtr)bytes[i].Int32High;
}
}
}
// Overload this to handle other types
protected virtual int Convert(bool unicode, object arg, ref PrimitiveToBytes primitiveToBytes)
{
int size;
if (arg == null)
{
primitiveToBytes.IntPtr = IntPtr.Zero;
size = IntPtr.Size;
}
else
{
Type type = arg.GetType();
TypeCode typeHandle = Type.GetTypeCode(type);
switch (typeHandle)
{
case TypeCode.Boolean:
// Boolean converted to Int32
primitiveToBytes.Int32 = (bool)arg ? 1 : 0;
size = IntPtr.Size;
break;
case TypeCode.SByte:
primitiveToBytes.SByte = (sbyte)arg;
size = IntPtr.Size;
break;
case TypeCode.Byte:
primitiveToBytes.Byte = (byte)arg;
size = IntPtr.Size;
break;
case TypeCode.Int16:
primitiveToBytes.Int16 = (short)arg;
size = IntPtr.Size;
break;
case TypeCode.UInt16:
primitiveToBytes.UInt16 = (ushort)arg;
size = IntPtr.Size;
break;
case TypeCode.Int32:
primitiveToBytes.Int32 = (int)arg;
size = IntPtr.Size;
break;
case TypeCode.UInt32:
primitiveToBytes.UInt32 = (uint)arg;
size = IntPtr.Size;
break;
case TypeCode.Int64:
primitiveToBytes.Int64 = (long)arg;
size = sizeof(long);
break;
case TypeCode.UInt64:
primitiveToBytes.UInt64 = (ulong)arg;
size = sizeof(ulong);
break;
case TypeCode.Single:
// Single converted to Double
primitiveToBytes.Double = (double)(float)arg;
size = sizeof(double);
break;
case TypeCode.Double:
primitiveToBytes.Double = (double)arg;
size = sizeof(double);
break;
case TypeCode.Char:
if (unicode)
{
primitiveToBytes.UInt16 = (char)arg;
}
else
{
byte[] bytes = Encoding.Default.GetBytes(new[] { (char)arg });
if (bytes.Length > 0)
{
primitiveToBytes.B0 = bytes[0];
if (bytes.Length > 1)
{
primitiveToBytes.B1 = bytes[1];
if (bytes.Length > 2)
{
primitiveToBytes.B2 = bytes[2];
if (bytes.Length > 3)
{
primitiveToBytes.B3 = bytes[3];
}
}
}
}
}
size = IntPtr.Size;
break;
case TypeCode.String:
{
string str = (string)arg;
GCHandle handle;
if (unicode)
{
handle = GCHandle.Alloc(str, GCHandleType.Pinned);
}
else
{
byte[] bytes = new byte[Encoding.Default.GetByteCount(str) + 1];
Encoding.Default.GetBytes(str, 0, str.Length, bytes, 0);
handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
}
handles.Add(handle);
primitiveToBytes.IntPtr = handle.AddrOfPinnedObject();
size = IntPtr.Size;
}
break;
case TypeCode.Object:
if (type == typeof(IntPtr))
{
primitiveToBytes.IntPtr = (IntPtr)arg;
size = IntPtr.Size;
}
else if (type == typeof(UIntPtr))
{
primitiveToBytes.UIntPtr = (UIntPtr)arg;
size = UIntPtr.Size;
}
else if (!type.IsValueType)
{
GCHandle handle = GCHandle.Alloc(arg, GCHandleType.Pinned);
primitiveToBytes.IntPtr = handle.AddrOfPinnedObject();
size = IntPtr.Size;
}
else
{
throw new NotSupportedException();
}
break;
default:
throw new NotSupportedException();
}
}
return size;
}
~VaList()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
for (int i = 0; i < handles.Count; i++)
{
if (handles[i].IsAllocated)
{
handles[i].Free();
}
}
handles.Clear();
}
public IntPtr AddrOfPinnedObject()
{
if (handles.Count == 0)
{
throw new ObjectDisposedException(GetType().Name);
}
return handles[0].AddrOfPinnedObject();
}
[StructLayout(LayoutKind.Explicit)]
protected struct PrimitiveToBytes
{
[FieldOffset(0)]
public byte B0;
[FieldOffset(1)]
public byte B1;
[FieldOffset(2)]
public byte B2;
[FieldOffset(3)]
public byte B3;
[FieldOffset(4)]
public byte B4;
[FieldOffset(5)]
public byte B5;
[FieldOffset(6)]
public byte B6;
[FieldOffset(7)]
public byte B7;
[FieldOffset(4)]
public int Int32High;
[FieldOffset(0)]
public byte Byte;
[FieldOffset(0)]
public sbyte SByte;
[FieldOffset(0)]
public short Int16;
[FieldOffset(0)]
public ushort UInt16;
[FieldOffset(0)]
public int Int32;
[FieldOffset(0)]
public uint UInt32;
[FieldOffset(0)]
public long Int64;
[FieldOffset(0)]
public ulong UInt64;
[FieldOffset(0)]
public float Single;
[FieldOffset(0)]
public double Double;
[FieldOffset(0)]
public IntPtr IntPtr;
[FieldOffset(0)]
public UIntPtr UIntPtr;
[FieldOffset(8)]
public int Size;
}
}
Example of use:
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int vprintf(string format, IntPtr ptr);
and
using (var list = new VaList(false, // Ansi encoding
true, // bool test
short.MinValue + 1, int.MinValue + 2, long.MinValue + 3, // signed
ushort.MaxValue - 4, uint.MaxValue - 5, ulong.MaxValue - 6, // unsigned
float.MaxValue, double.MaxValue, // float/double
'A', "Foo", Encoding.Default.GetBytes("Bar\0"), null, // char/string
IntPtr.Size == sizeof(int) ? (IntPtr)(int.MinValue + 7) : (IntPtr)(long.MinValue + 7), // signed ptr
UIntPtr.Size == sizeof(uint) ? (UIntPtr)(uint.MaxValue - 8) : (UIntPtr)(ulong.MaxValue - 8))) // unsigned ptr
{
vprintf("%d\n %hd\n %d\n %lld\n %hu\n %u\n %llu\n %f\n %f\n %c\n %s\n %s\n %s\n %p\n %p\n", list.AddrOfPinnedObject());
}
Note that this code is compatible only with Visual C++ for Intel x86/x64. ARM uses another format, and GCC still other formats.
I found a opensource code that was a much simpler version of NAudio for my C# application. Which for me is better because all I am looking to do is play a brief sound out of the speakers to test that they are plugged in and working, and I also want to listen to the microphone. The project it self looked ok, but i felt that it could be refactored a bit into smaller chucks. Another thing i found is that the WaveOutBuffer.cs and WaveInBuffer.cs files were remarkably similar. So i started to make a abstract class WaveBuffer. This would have all the similar functions and variables in it that would be passed. One that i am having troubles with is as follows. Another file WaveNative.cs has delegate in it. I am very new to delegates and Events so i know it has the potential to be very important. but i dont like the way that it is setup to be used. So i'll post what Is in each file and how it is used, then show what i have been trying to get to work. Maybe between all of our minds we can consolidate and refactor this to make it more efficient :)
so First.
WaveNative.cs
//callbacks
public delegate void WaveDelegate(IntPtr hdrvr, int uMsg, int dwUser, ref WaveHdr wavhdr, int dwParam2);
WaveInBuffer.cs / WaveOutBuffer.cs
internal static void WaveInProc(IntPtr hdrvr, int uMsg, int dwUser, ref WaveNative.WaveHdr wavhdr, int dwParam2)
{
if (uMsg == WaveNative.MM_WIM_DATA)
{
try
{
GCHandle h = (GCHandle)wavhdr.dwUser;
WaveInBuffer buf = (WaveInBuffer)h.Target;
buf.OnCompleted();
}
catch
{
}
}
}
//WaveOutBuffer.cs version
internal static void WaveOutProc(IntPtr hdrvr, int uMsg, int dwUser, ref WaveNative.WaveHdr wavhdr, int dwParam2)
{
if (uMsg == WaveNative.MM_WOM_DONE)
{
try
{
GCHandle h = (GCHandle)wavhdr.dwUser;
WaveOutBuffer buf = (WaveOutBuffer)h.Target;
buf.OnCompleted();
}
catch
{
}
}
}
WaveInRecorder.cs / WaveOutRecorder
private WaveNative.WaveDelegate m_BufferProc = new WaveNative.WaveDelegate(WaveInBuffer.WaveInProc);
private WaveNative.WaveDelegate m_BufferProc = new WaveNative.WaveDelegate(WaveOutBuffer.WaveOutProc);
In the end they are used for a PInvoke call as follows
[DllImport(mmdll)]
public static extern int waveOutOpen(out IntPtr hWaveOut, int uDeviceID, WaveFormat lpFormat, WaveDelegate dwCallback, int dwInstance, int dwFlags);
[DllImport(mmdll)]
public static extern int waveInOpen(out IntPtr phwi, int uDeviceID, WaveFormat lpFormat, WaveDelegate dwCallback, int dwInstance, int dwFlags);
I've consolidated most the other things in the abstract version of WaveBuffer such as the HeaderData, the size of the header, the IntPtr data, a GCHandle HeaderHandle, and HeaderDataHandle. A WaitFor command a OnCompleteCommand, a bool Busy, and a AutoResetEvent. Not sure what it is used for but it's used for, but it is used the same in each file so i just moved it over. Thank you for your patience and reading through this thread.
EDIT
sorry for the confusion, i got so wrapped up in finding all this stuff I forgot to ask what i was meaning to ask. Basically teh question is How can I combine these 2 functions that do nearly EXACTLY the same thing? How does this Delegate work from WaveNative such that i can make a new instance in WaveInBuffer/WaveOutBuffer and it means the same thing. I just assumed that I had to always either call the one from the other or just call the base class one. As for m_BufferedProc I'll post the entire code since it is hard for me to understand. Mind you this code I'm posting is not my own. Here it is
public class WaveInRecorder : IDisposable
{
private IntPtr m_WaveIn;
private WaveInBuffer m_Buffers; // linked list
private WaveInBuffer m_CurrentBuffer;
private Thread m_Thread;
private BufferDoneEventHandler m_DoneProc;
private bool m_Finished;
private WaveNative.WaveDelegate m_BufferProc = new WaveNative.WaveDelegate(WaveInBuffer.WaveInProc);
public static int DeviceCount
{
get { return WaveNative.waveInGetNumDevs(); }
}
public WaveInRecorder(int device, WaveFormat format, int bufferSize, int bufferCount, BufferDoneEventHandler doneProc)
{
m_DoneProc = doneProc;
WaveInHelper.Try(WaveNative.waveInOpen(out m_WaveIn, device, format, m_BufferProc, 0, WaveNative.CALLBACK_FUNCTION));
AllocateBuffers(bufferSize, bufferCount);
for (int i = 0; i < bufferCount; i++)
{
SelectNextBuffer();
m_CurrentBuffer.Record();
}
WaveInHelper.Try(WaveNative.waveInStart(m_WaveIn));
m_Thread = new Thread(new ThreadStart(ThreadProc));
m_Thread.Start();
}
~WaveInRecorder()
{
Dispose();
}
public void Dispose()
{
if (m_Thread != null)
try
{
m_Finished = true;
if (m_WaveIn != IntPtr.Zero)
WaveNative.waveInReset(m_WaveIn);
WaitForAllBuffers();
m_Thread.Join();
m_DoneProc = null;
FreeBuffers();
if (m_WaveIn != IntPtr.Zero)
WaveNative.waveInClose(m_WaveIn);
}
finally
{
m_Thread = null;
m_WaveIn = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
private void ThreadProc()
{
while (!m_Finished)
{
Advance();
if (m_DoneProc != null && !m_Finished)
m_DoneProc(m_CurrentBuffer.Data, m_CurrentBuffer.Size);
m_CurrentBuffer.Record();
}
}
private void AllocateBuffers(int bufferSize, int bufferCount)
{
FreeBuffers();
if (bufferCount > 0)
{
m_Buffers = new WaveInBuffer(m_WaveIn, bufferSize);
WaveInBuffer Prev = m_Buffers;
try
{
for (int i = 1; i < bufferCount; i++)
{
WaveInBuffer Buf = new WaveInBuffer(m_WaveIn, bufferSize);
Prev.NextBuffer = Buf;
Prev = Buf;
}
}
finally
{
Prev.NextBuffer = m_Buffers;
}
}
}
private void FreeBuffers()
{
m_CurrentBuffer = null;
if (m_Buffers != null)
{
WaveInBuffer First = m_Buffers;
m_Buffers = null;
WaveInBuffer Current = First;
do
{
WaveInBuffer Next = Current.NextBuffer;
Current.Dispose();
Current = Next;
} while(Current != First);
}
}
private void Advance()
{
SelectNextBuffer();
m_CurrentBuffer.WaitFor();
}
private void SelectNextBuffer()
{
m_CurrentBuffer = m_CurrentBuffer == null ? m_Buffers : m_CurrentBuffer.NextBuffer;
}
private void WaitForAllBuffers()
{
WaveInBuffer Buf = m_Buffers;
while (Buf.NextBuffer != m_Buffers)
{
Buf.WaitFor();
Buf = Buf.NextBuffer;
}
}
Mind you that that code is not mine but rather it is Ianier Munoz's. I have a similar version I'm working on, you can browse the code that i extracted from it at http://code.google.com/p/adli/source/browse/#svn%2Ftrunk%2FAspects%2FCustom%2FAudio
how I use it (not fully implemented is at here)
http://code.google.com/p/adli/source/browse/trunk/Aspects/Panels/Main%20Panels/AudioBrightnessPanel.cs
look at the action listener for my microphone test.
again sorry for the confusion i will try not to post a question without a question again.
well you've got mutually exclusive if blocks which means its pretty easy to merge the 2 together... (i removed the empty catch block because its evil)
internal static void WaveProc(IntPtr hdrvr, int uMsg, int dwUser, ref WaveNative.WaveHdr wavhdr, int dwParam2)
{
GCHandle h = (GCHandle)wavhdr.dwUser;
if (uMsg == WaveNative.MM_WIM_DATA)
{
WaveInBuffer buf = (WaveInBuffer)h.Target;
buf.OnCompleted();
}
if (uMsg == WaveNative.MM_WOM_DONE)
{
WaveOutBuffer buf = (WaveOutBuffer)h.Target;
buf.OnCompleted();
}
}
private WaveNative.WaveDelegate m_BufferProc = new WaveNative.WaveDelegate(WaveInBuffer.WaveProc);
I created the type IntPtr<T> to act like a generic pointer that c/c++ have:
public struct IntPtr<T> : IDisposable where T : struct
{
private static Dictionary<IntPtr, GCHandle> handles = new Dictionary<IntPtr, GCHandle>();
private IntPtr ptr;
public IntPtr(ref T value)
{
GCHandle gc = GCHandle.Alloc(value, GCHandleType.Pinned);
ptr = gc.AddrOfPinnedObject();
handles.Add(ptr, gc);
}
public IntPtr(ref T[] value)
{
GCHandle gc = GCHandle.Alloc(value, GCHandleType.Pinned);
ptr = gc.AddrOfPinnedObject();
handles.Add(ptr, gc);
}
public IntPtr(IntPtr value)
{ ptr = value; }
public IntPtr(IntPtr<T> value)
{ ptr = value.ptr; }
public void Dispose()
{
if (handles.ContainsKey(ptr))
{
GCHandle gc = handles[ptr];
gc.Free();
handles.Remove(ptr);
ptr = IntPtr.Zero;
}
}
public T? this[int index]
{
get
{
if (ptr == IntPtr.Zero) return null;
if (index < 0) throw new IndexOutOfRangeException();
if (handles.ContainsKey(ptr))
{
GCHandle gc = handles[ptr];
if (gc.Target is Array) return ((T[])gc.Target)[index];
return (T)gc.Target;
}
return null;
}
set
{
if (index < 0) throw new IndexOutOfRangeException();
// not yet implemented
}
}
private T[] getArray()
{
if (handles.ContainsKey(ptr)) return (T[])handles[ptr].Target;
return null;
}
public int Count
{
get
{
if(handles.ContainsKey(ptr))
{
GCHandle gc = handles[ptr];
if (gc.Target is Array) return ((T[])gc.Target).Length;
return 1;
}
return 0;
}
}
public static implicit operator IntPtr(IntPtr<T> value) { return value.ptr; }
public static implicit operator T(IntPtr<T> value) { return (T)value[0]; }
public static implicit operator T[](IntPtr<T> value) { return value.getArray(); ; }
public static implicit operator T?(IntPtr<T> value) { return value[0]; }
}
It's not complete yet but for now it works, the problem is i keep track of GCHandle by storing them in handles now i need to free the GCHandle once it no more needed so i have to declare a destrcutor but c# don't allow struct to have destrcutor or to override 'Finalize' method and if the such variable of type IntPtr<T> goes out of scope the destruction take place but the GCHandle won't be free.
UPDATE
As an example of this class usage, suppose we going to interpo COAUTHIDENTITY and COAUTHINFO from COM, here what it will look like:
[StructLayout(LayoutKind.Sequential)]
struct COAUTHIDENTITY
{
[MarshalAs(UnmanagedType.LPWStr)] string User;
uint UserLength;
[MarshalAs(UnmanagedType.LPWStr)] string Domain;
uint DomainLength;
[MarshalAs(UnmanagedType.LPWStr)] string Password;
uint PasswordLength;
uint Flags;
}
[StructLayout(LayoutKind.Sequential)]
struct COAUTHINFO
{
uint dwAuthnSvc;
uint dwAuthzSvc;
[MarshalAs(UnmanagedType.LPWStr)] string pwszServerPrincName;
uint dwAuthnLevel;
uint dwImpersonationLevel;
IntPtr<COAUTHIDENTITY> pAuthIdentityData;
uint dwCapabilities;
}
Instead to make pAuthIdentityData an IntPtr and use Marshal member functions to get object of type COAUTHIDENTITY, IntPtr<T> will make it more simple.
The question is: where should i write the code to free GCHandle when the IntPtr<T> is released?
You're reinventing the wheel. Look at the SafeHandle class. Use an existing descendant or create your own descendant.
I would like to know if there is a way to determine CPU cache size in managed code?
I am writing a Strassen's algorithm for matrix multiplication in C# and would like to know how many elements of the matrices I could fit into cache to improve computational speed.
You can use WMI to retrieve cache information.
You will first need to add a reference to System.Management.dll to your project, then you can use the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
namespace Scratch
{
public enum CacheLevel : ushort
{
Level1 = 3,
Level2 = 4,
Level3 = 5,
}
public static class CPUInfo
{
public static List<uint> GetCacheSizes(CacheLevel level)
{
ManagementClass mc = new ManagementClass("Win32_CacheMemory");
ManagementObjectCollection moc = mc.GetInstances();
List<uint> cacheSizes = new List<uint>(moc.Count);
cacheSizes.AddRange(moc
.Cast<ManagementObject>()
.Where(p => (ushort)(p.Properties["Level"].Value) == (ushort)level)
.Select(p => (uint)(p.Properties["MaxCacheSize"].Value)));
return cacheSizes;
}
}
}
Full details of the Win32_CacheMemory WMI class is available at:
http://msdn.microsoft.com/en-us/library/aa394080(v=vs.85).aspx
is this what you are looking for? The Win32_Processor class features L2CacheSize and L3CacheSize members.
using System;
using System.Runtime.InteropServices;
class Processor
{
[DllImport("kernel32.dll")]
public static extern int GetCurrentThreadId();
//[DllImport("kernel32.dll")]
//public static extern int GetCurrentProcessorNumber();
[StructLayout(LayoutKind.Sequential, Pack = 4)]
private struct GROUP_AFFINITY
{
public UIntPtr Mask;
[MarshalAs(UnmanagedType.U2)]
public ushort Group;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.U2)]
public ushort[] Reserved;
}
[DllImport("kernel32", SetLastError = true)]
private static extern Boolean SetThreadGroupAffinity(IntPtr hThread, ref GROUP_AFFINITY GroupAffinity, ref GROUP_AFFINITY PreviousGroupAffinity);
[StructLayout(LayoutKind.Sequential)]
public struct PROCESSORCORE
{
public byte Flags;
};
[StructLayout(LayoutKind.Sequential)]
public struct NUMANODE
{
public uint NodeNumber;
}
public enum PROCESSOR_CACHE_TYPE
{
CacheUnified,
CacheInstruction,
CacheData,
CacheTrace
}
[StructLayout(LayoutKind.Sequential)]
public struct CACHE_DESCRIPTOR
{
public byte Level;
public byte Associativity;
public ushort LineSize;
public uint Size;
public PROCESSOR_CACHE_TYPE Type;
}
[StructLayout(LayoutKind.Explicit)]
public struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION
{
[FieldOffset(0)]
public PROCESSORCORE ProcessorCore;
[FieldOffset(0)]
public NUMANODE NumaNode;
[FieldOffset(0)]
public CACHE_DESCRIPTOR Cache;
[FieldOffset(0)]
private UInt64 Reserved1;
[FieldOffset(8)]
private UInt64 Reserved2;
}
public enum LOGICAL_PROCESSOR_RELATIONSHIP
{
RelationProcessorCore,
RelationNumaNode,
RelationCache,
RelationProcessorPackage,
RelationGroup,
RelationAll = 0xffff
}
public struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
{
#pragma warning disable 0649
public UIntPtr ProcessorMask;
public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
public SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION ProcessorInformation;
#pragma warning restore 0649
}
[DllImport(#"kernel32.dll", SetLastError = true)]
public static extern bool GetLogicalProcessorInformation(IntPtr Buffer, ref uint ReturnLength);
private const int ERROR_INSUFFICIENT_BUFFER = 122;
private static SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] _logicalProcessorInformation = null;
public static SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] LogicalProcessorInformation
{
get
{
if (_logicalProcessorInformation != null)
return _logicalProcessorInformation;
uint ReturnLength = 0;
GetLogicalProcessorInformation(IntPtr.Zero, ref ReturnLength);
if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
{
IntPtr Ptr = Marshal.AllocHGlobal((int)ReturnLength);
try
{
if (GetLogicalProcessorInformation(Ptr, ref ReturnLength))
{
int size = Marshal.SizeOf(typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
int len = (int)ReturnLength / size;
_logicalProcessorInformation = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[len];
IntPtr Item = Ptr;
for (int i = 0; i < len; i++)
{
_logicalProcessorInformation[i] = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION)Marshal.PtrToStructure(Item, typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
Item += size;
}
return _logicalProcessorInformation;
}
}
finally
{
Marshal.FreeHGlobal(Ptr);
}
}
return null;
}
}
}
Handy helper function:
public static void GetPerCoreCacheSizes(out Int64 L1, out Int64 L2, out Int64 L3)
{
L1 = 0;
L2 = 0;
L3 = 0;
var info = Processor.LogicalProcessorInformation;
foreach (var entry in info)
{
if (entry.Relationship != Processor.LOGICAL_PROCESSOR_RELATIONSHIP.RelationCache)
continue;
Int64 mask = (Int64)entry.ProcessorMask;
if ((mask & (Int64)1) == 0)
continue;
var cache = entry.ProcessorInformation.Cache;
switch (cache.Level)
{
case 1: L1 = L1 + cache.Size; break;
case 2: L2 = L2 + cache.Size; break;
case 3: L3 = L3 + cache.Size; break;
default:
break;
}
}
And call it:
static void Main(string[] args)
{
long l1, l2, l3;
GetPerCoreCacheSizes(out l1, out l2, out l3);
String s = String.Format("Single-core memory cache: L1={0} KB, L2={1} KB, L3={2} KB", l1 / 1024, l2 / 1024, l3 / 1024);
Console.WriteLine(s);
Console.ReadLine();
}
Output:
Single-core memory cache: L1=64 KB, L2=256 KB, L3=6144 KB
Try this code
using System.Management;
uint32 cachsize;
public void CPUSpeed()
{
using(ManagementObject Mo = new ManagementObject("Win32_Processor.DeviceID='CPU0'"))
{
cachsize = (uint)(Mo["L2CacheSize"]);
}
}
I get it from Here