C++이나 C#에서 RAM내부의데이터를 다른위치로 옮기는 효율적인 방법이 있을까요?

waka@Google의 이미지

RAM에 올라와있는 데이터중 대략 1~3GB정도의 데이터를 RAM의 다른 위치로 옮기는 작업을 하려고 합니다.
(여러번 반복해서 수행합니다)

Parallel.For문 안에서 Buffer.MemoryCopy함수를 이용해서 옮겨보니, CPU점유율도 너무 많이 사용하고, 시간도 오래걸리네요

지금 프로그램에서 다른 연산을 수행하느라 이미 점유율을 8~90%정도 사용하고있어서 리소스를 대기하느라

오래걸리는 것 같기도 합니다.

DMA같은 방식도 찾아보았는데, 이건 주변장치와 통신할때만 가능한 것으로 보이네요.

혹시 CPU점유율을 최소화 하거나, 빠른 속도로 RAM내부의 데이터를 다른 위치로 옮기는 방법을 아시는분이 있으실까요??

라스코니의 이미지

시간이 얼마나 걸리는 데요? Buffer.MemoryCopy() 함수를 사용할 때 몇 바이트씩 옮기고 계신가요?
이 문제는 메모리 대역폭 보다는 캐쉬나 최적화 문제와 가깝습니다. 최근 기술의 메모리 대역폭은 정말 빠르거든요.

데이터를 옮길 때 캐쉬에 잘 들어갈 수 있도록 100kb 블럭 단위로 해보시고 사이즈도 점점 키워가면서 테스트해 보세요. 한 5 ~ 10 Mbytes 씩 옮겨도 될 것 같은데요.

waka@Google의 이미지

50000 * 50000정도의 이미지를 복사하는데, 이미지가 1TB정도의 램에 적재되어 있습니다.
이미지가 연속적으로 그려져있지 않아서, 50000을 복사하고 다음위치를 찾아서 50000을 복사하고
이런 복사를 50000번 반복합니다.

Parallel.For문으로 병렬로 복사하면 170~200ms정도 소요되지만, 4~50%정도의 CPU부하가 발생합니다.
For문으로 복사하면 4~500ms정도 소요되고 10%내외의 부하가 발생합니다.

만약에 8~90%의 외부부하가 추가되면 속도는 4~5배정도 더 소요됩니다.
연속적인 데이터가 아니라서, 100kb정도를 한번에 인자로 넣을 수는 없을 것 같은데 다른방법은 없을까요?

라스코니의 이미지

그 정도 수준이라면 더 최적화할 수 있는 여지는 많지 않아 보입니다.
다음 위치를 찾는 path를 좀 더 단축하고, 한꺼번에 수 Mbyte씩 옮기는 것이 가능한지 찾아보시라고 하고 싶네요.

라스코니의 이미지

이렇게 한번 해보세요. 두부분으로 나누어서 처리하면 좀 더 캐시 활용에 유리한 방향으로 될 수 있습니다.

1) 먼저, 다음 위치를 찾는 작업을 미리 다 수행해서 다음 위치를 배열로 따로 저장
2) 루프 내에서는 배열을 참조해서 메모리 복사만 수행

익명 사용자의 이미지

현재 Copy하는 코드는 아래와 같습니다.
public void BufferCopy(InspInfo info)
{
Info = info;
unsafe
{
IntPtr src = (IntPtr)(m_srcPtr.ToInt64() + (info.lY * m_lSrcWidth) + info.lX);
long lsrc = src.ToInt64();
long ldst = m_dstPtr.ToInt64();

Parallel.For(0, info.lChipHeight, (y) =>
{
IntPtr srcPtr = (IntPtr)(lsrc + m_lSrcWidth * y);
IntPtr dstPtr = (IntPtr)(ldst + m_lDstWidth * y);
Buffer.MemoryCopy(srcPtr.ToPointer(), dstPtr.ToPointer(), info.lChipWidth, info.lChipWidth);
});
}
}

이 코드에서,

IntPtr srcPtr = (IntPtr)(lsrc + m_lSrcWidth * y);
IntPtr dstPtr = (IntPtr)(ldst + m_lDstWidth * y); 이렇게 주소 계산하는 코드를
밖에서 배열로 담아서 참조만 하는식으로 계산하라는 말씀이신거죠??
그런데, Buffer.MemoryCopy코드를 한번에 MByte단위로 할 수 있는 방법이 있을까요??
2차원 이미지에서 특정 영역만 골라서 Copy하는 방식이라서 어떻게 해야할지 모르겠네요 ㅠ

라스코니의 이미지

맞습니다. 따로 주소 계산 결과를 배열로 저장하는 것을 먼저 수행하고 그 다음에 이를 참조해서 메모리 복사만 수행하는 것입니다.

복사하는 주소 연산의 결과가 최대한 근접하면 좋습니다. 계산 결과를 의도적으로 이것을 감안해서 낸다면 캐시 활용에 좋은 결과를 낼 것이고요. 예를 들어 한 영역을 복사하고 다음 영역을 복사할 때 가능한 근접한 주소 영역이 선택되도록 하는 것이 좋습니다. ABCDEF.....XYZ 이렇게 주소 영역이 serialize되어 있다고 한다면 가장 안좋은 방법이 AZBYCX.... 이런식으로 점프해서 액세스하는 것이 되겠죠.

익명 사용자의 이미지

IntPtr srcPtr = (IntPtr)(lsrc + m_lSrcWidth * y);
IntPtr dstPtr = (IntPtr)(ldst + m_lDstWidth * y);

메모리 주소계산 코드가 이렇다면..
데이터가 모여있다는것 아닌가요?

라스코니의 이미지

예를들면, 첫줄은 y = ax + b와 형식이 같네요.
a(기울기)가 충분히 크면 x의 사소한 변화에도 큰 결과값의 변화가 생기게 됩니다.
그 변화가 캐쉬의 여유 공간보다 크게 되면 캐쉬를 비우고 다시 채우고, 또 비우고 다시 채우는 일이 반복됩니다. 성능 저하가 예상될 수 있죠.

익명 사용자의 이미지

IntPtr srcPtr = (IntPtr)(lsrc + m_lSrcWidth * y);
IntPtr dstPtr = (IntPtr)(ldst + m_lDstWidth * y);

메모리 주소계산 코드가 이렇다면..
데이터가 모여있다는것 아닌가요?

익명 사용자의 이미지

실수 했습니다.
lChipWidth 값에 따라 연속적이 아닐 수 있겠네요.
잘못알고 글을 썼습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.