Почему моя функция C++ выполняется в 10 раз быстрее, чем вызов C# P/Invoke?C#

Место общения программистов C#
Ответить
Anonymous
 Почему моя функция C++ выполняется в 10 раз быстрее, чем вызов C# P/Invoke?

Сообщение Anonymous »

У меня есть функция C++, которая использует встроенные функции AVX2 для повышения яркости изображения. Когда я измеряю производительность непосредственно в C++, обработка изображения с разрешением 3840 x 240 занимает около 500 микросекунд. Однако когда я вызываю ту же функцию из C# с помощью P/Invoke, это занимает около 4 миллисекунд, что очень много. медленнее.
Для изображения 3840 x 2160 собственный C++ занимает около 1,5 мс, а P/Invoke — около 4,5 мс.
Для изображения 10000 x 4000 Нативный C++ изображения занимает около 3 мс, а P/Invoke — около 8 мс.
Вот моя настройка:
C++: встроенная функция, которая обрабатывает данные изображения с помощью AVX2.
C#: использует P/Invoke для вызова этой функции, передавая данные изображения непосредственно по ссылке.
Основная программа C#:

Код: Выделить всё

static void Main(string[] args)
{
int width = 3840;
int height = 240;
byte[] image = new byte[width * height];
Random random = new Random();

// Fill the image array with random brightness values between 0 and 255
for (int i = 0; i < image.Length; i++)
{
image[i] = (byte)random.Next(0, 256);
}

byte brightness = 30;

// Measure C# processing time
Stopwatch sw = Stopwatch.StartNew();
ProcessorCSharp.BrightenImage(image, brightness);
sw.Stop();

Console.WriteLine("C# Time: {0} microseconds", sw.Elapsed.TotalMilliseconds * 1000);
}
Класс-оболочка C#:

Код: Выделить всё

public class ProcessorCSharp
{
[DllImport("ImageProcessingLib.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void brightenImageSIMD(IntPtr image, int size, byte brightness);

public static unsafe void BrightenImage(byte[] image, byte brightness)
{
int size = image.Length;

fixed (byte* p = image)
{
brightenImageSIMD((IntPtr)p, size, brightness);
}
}
}
Функция C++:

Код: Выделить всё

#include   // AVX2 intrinsics
#include 
#include     // For std::min

extern "C" __declspec(dllexport) // in my main c++ code this line doesn't exist
void brightenImageSIMD(uint8_t* image, size_t size, uint8_t brightness) {
size_t i = 0;
__m256i brightnessVector = _mm256_set1_epi8(brightness);
__m256i maxVector = _mm256_set1_epi8(255);

for (; i + 31 < size; i += 32) {
__m256i pixels = _mm256_loadu_si256((__m256i*) &image[i]);
__m256i brightened = _mm256_adds_epu8(pixels, brightnessVector);
__m256i clamped = _mm256_min_epu8(brightened, maxVector);
_mm256_storeu_si256((__m256i*) &image[i], clamped);
}

for (; i < size; ++i) {
image[i] = std::min(image[i] + brightness, 255);
}
}

// Helper function to measure execution time
template 
long long measureExecutionTime(Func func, Args&&... args) {
auto start = std::chrono::high_resolution_clock::now();
func(std::forward(args)...);
auto end = std::chrono::high_resolution_clock::now();
return std::chrono::duration_cast(end - start).count();
}

int main() {
const int width = 3840;
const int height = 2160;
const uint8_t brightnessIncrease = 30;

std::vector image(width * height);

// Set up random number generation
std::random_device rd;  // Seed for the random number engine
std::mt19937 gen(rd()); // Standard mersenne_twister_engine
std::uniform_int_distribution dis(0, 255); // Range from 0 to 255 for 8-bit brightness levels

// Fill the image with random values
for (auto& pixel : image) {
pixel = static_cast(dis(gen));
}

// Measure performance of SIMD method
auto imageCopy3 = image; // Make another copy for fair comparison
long long timeSIMD = measureExecutionTime(brightenImageSIMD, imageCopy3, brightnessIncrease);

std::cout 

Подробнее здесь: [url]https://stackoverflow.com/questions/79169428/why-does-my-c-function-run-10x-faster-than-the-c-sharp-p-invoke-call[/url]
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»