2010-04-24 5 views
4

F #에는 NativePtr 모듈이 있지만 System.IntPtr과 마찬가지로 '추가/가져 오기/설정 기능을위한 32 비트 오프셋 만 지원하는 것 같습니다.포인터에 64 비트 오프셋 추가

F #에서 기본 포인터 (nativeptr < 'a>)에 64 비트 오프셋을 추가하는 방법이 있습니까? 물론 모든 주소를 64 비트 정수로 변환하고 일반 정수 연산을 수행 한 다음 결과를 nativeptr < 'a>에 다시 변환 할 수 있지만 추가 및 imul 명령어가 추가로 발생합니다. AGU가 주소 계산을 수행하기를 정말로 원합니다. 이 유형 매개 변수에 대한 "관리되지 않는"제약이 없지만, 때문에 실제로 , 수 없습니다 적어도 당신이 할 수있는 당신이

void* ptr = Marshal.AllocHGlobal(...).ToPointer(); 
int64 offset = ...; 
T* newAddr = (T*)ptr + offset; // T has to be an unmanaged type 

음과 같은 일을 할 수있는 C#으로 안전하지 않은 사용 예를 들어

, 비 일반 일반 포인터 연산 방식.

F #에서는 마침내 관리되지 않는 제약 조건이 있습니다. 하지만 포인터 연산은 어떻게해야합니까?

+0

처음에는 "너는 그렇게 할 수 없다"는 생각이 들었지 만 포인터의 오프셋을 다시 생각해 보면 커다란 메모리가 연속적으로 할당되어 있다면 포인터 오프셋 만 이해할 수 있습니다. 4GiB보다 큰 연속 할당 배열의 사용 사례는 무엇입니까? – sblom

+0

@sblom : 이미징 데이터는 쉽게 4 GiB를 초과 할 수 있습니다.) 물론 데이터 등을 파티션 할 수 있습니다. 하지만 할당 된 연속 메모리의 양을 더 많이 사용할 수 있다면 어떻게하는지 알고 싶습니다. – Frank

답변

2

,하지만 난의 F 번호의 구현을 살펴했다 NativePtr 모듈을 생각하면 nativeptr<'a>nativeint으로 변환하는 것과 관련된 성능 오버 헤드가 없다고 생각합니다.

구현은 인라인 IL을 사용하고 인라인 IL 코드는 코드가 포함되어 있지 않습니다 - 그것은 단지 F # 컴파일러는 스택에 값이 다른 유형이 있음을 생각하게하는이 :

let inline ofNativeInt (x:nativeint) = (# "" x : nativeptr<_> #) 
let inline toNativeInt (x:nativeptr<_>) = (# "" x : nativeint #) 

에서을 실제로 NativePtr.add 메서드는이 두 메서드를 사용합니다. 포인터를 nativeint으로 변환 한 다음 32 비트 정수 ('a 형식의 크기를 곱한 값)를 더합니다.

그래서, 다음과 같은 기능을 잘해야한다 : 코드에서 사용

let inline addNativeInt (x:nativeptr<'a>) (n:nativeint) : nativeptr<'a> = 
    (NativePtr.toNativeInt x) + n |> NativePtr.ofNativeInt 

모든 기능이 인라인해야합니다, 당신은 또한 (비록 내가 확인하지 않은 단지 하나의 명령으로 끝날 것 때문에 그). 코드에서 여러 번 함수를 사용하는 것에 대해 걱정할 필요가 없습니다 (항상 nativeptr<'a>로 작업하고이 함수를 사용하여 추가 할 수 있습니다).

그러나 분할 데이터도 옵션 일 수 있습니다. 필자가 아는 한 F #을 사용하여 일부 큰 (> 2GB) 데이터 세트를 처리하는 MSR 팀은 정확히이 접근 방식을 사용했습니다. 데이터를 2GB 블록으로 분할했습니다. 배열에 저장).

+0

+1 매우 흥미 롭습니다. 감사합니다. 또한 NativePtr을 조사하려고했지만 적어도 Reflector는 "//이 항목은 난독 화되어 번역 할 수 없습니다."라고 표시합니다. – Frank

+2

@Novox : Visual Studio 2008의 F # 버전을 다운로드 할 수 있습니다. 소스 코드와 함께 제공됩니다 ('source' 디렉토리에 있음). 이것은 매우 유용한 정보 소스입니다 :-). 반사경이 코드에 대처할 수 없다는 것은 재미 있습니다! –

+0

+1 내가 할거야.이게 쓸모가있을거야. – Frank

1

촬상 데이터 용이 4 지브 를 초과 할 수있다)

그렇지 캔, 64 코드는 +/- 2 GB의 제한을 상쇄 갖는다. .NET에서 2GB보다 큰 배열을 할당 할 수없는 이유 중 하나입니다. 이 제한은 관리되지 않는 64 비트 C/C++ 코드에도 존재합니다. WIC와 같이이 제한 사항을 해결하는 라이브러리가 있지만 주소는 입니다. 비트 맵 비트의은 모두 사용할 때 의미가 없습니다.

그럼에도 불구하고, C#으로 긴에 IntPtr입니다 캐스팅에 의해 이러한 주소를 생성 할 수 있습니다 :이 분야의 전문가가 아니에요

IntPtr addr = SomeCall(); 
long offset = blah; 
addr = (IntPtr)((long)addr + offset); 
+0

첫 번째 : 내 질문에 말했듯이, 나는 길게 캐스트하고 싶지 않다. 포인터 연산에 AGU를 사용하고 싶다. 두 번째 : AllocHGlobal (Win32의 GlobalAlloc)은 x64에서 2 GiB를 행복하게 할당합니다. 그래서 "+/- 2 GB 오프셋 제한"이란 무엇입니까? – Frank

+0

할당 제한이 아니라 주소 지정 제한 사항입니다. 정확히 2GB가 넘는 주소를 지정해야하는 이유를 정확하게 보여줌으로써이 스레드를 계속 움직이십시오. AGU는 나에게 또 다른 애매한 3 글자 약어입니다. –

+0

AGU는 CPU의 _A_ddress _G_eneration _U_nit입니다. 해당 오프셋 제한에 대한 참조가 있습니까? 왜 내가 필요한거야? 계산 노드 당 32 GiB RAM의 HPC 클러스터를 사용한다면 제대로 활용하고 싶습니까? FEM 강성 행렬은 비록 희소하더라도 복잡한 모델에 대해 상당히 커질 수 있습니다. 수백만 개의 유한 체적 셀을 가진 CFD 시뮬레이션을위한 더 많은 것. 또는 MRT 이미지 등의 일관성 강화 확산 이미지 필터링과 같은 애플리케이션을 생각해보십시오. – Frank